/* ─────────────────────────────────────────────────────────────────────────────
   Tokens e base.  (L-44)

   Vindos do protótipo `l01-pencil.html`, validados no iPad e no Mac nos
   Blocos A e B — não reinventados aqui. As duas decisões que mais importam:

   1. A medida da coluna é em **em**, não em rem. A coluna cresce junto com a
      fonte, e o número de caracteres por linha fica estável em qualquer
      tamanho — foi o achado da rodada 1 da L-03, no iPad.
   2. As cores de destaque têm variante por tema, calibradas para o texto
      seguir acima de 4.5:1 **por cima do destaque** (03-destaques §5.1).
   ───────────────────────────────────────────────────────────────────────── */

/* ── fontes ───────────────────────────────────────────────────────────────
   Os três `@font-face` e os tokens de família subiram ao núcleo (Task 9,
   Scriptorium). O que fica aqui é só o vocabulário de destino: os blocos
   `[data-fonte=…]` abaixo apontam para `--serif`, `--serif-leitura` e
   `--sans`, que o `nucleo.css` declara.
   ───────────────────────────────────────────────────────────────────────── */

:root {
  --size-base: clamp(1.125rem, 1.02rem + 0.5vw, 1.345rem);
  --size: calc(var(--size-base) + var(--tamanho, 0) * 0.0625rem);
  --leading: 1.6;
  /* Espaço entre a coluna e a beirada da folha. Mora no `:root` desde a
     L-74: o `main` também precisa dele para reservar a margem da marginália. */
  --respiro: clamp(1.5rem, 5vw, 4rem);
  /* A medida virou DERIVADA com o espaçamento para dislexia (Bloco J2): a
     largura que o leitor escolhe entra em `--medida-base`, e `--fator-espaco`
     multiplica. Os dois se separaram porque a compensação de medida precisa
     valer para as TRÊS larguras, e não só para a padrão — a conta está na
     nota de `[data-espacamento]`, abaixo. Com o fator em 1, que é o padrão,
     o valor computado continua sendo o mesmo `34.5em` de sempre. */
  --medida-base: 34.5em;
  --measure: calc(var(--medida-base) * var(--fator-espaco, 1));
  --space-para: 0.9em;
  --space-block: 2.2em;

  /* Charter (spec 50 §3.6): do sistema da Apple, zero byte no casco. A pilha
     cai em serifas de desenho parecido onde ela não existe. */
  --serif-charter: Charter, "Bitstream Charter", "Sitka Text", Cambria, serif;

  /* ── Duas famílias de cor, e a distinção é o conserto da L-51b ───────────
     `--hl-*` é a cor de **marcação**: ela entra POR BAIXO DO TEXTO, e por isso
     muda com o tema (03 §5.1). `--vivo-*` é a cor de **amostra**: aparece em
     botão e em bolinha, sobre fundo de cromo, e não muda nunca — a amostra
     precisa ser reconhecível como "a azul", e uma azul escurecida para o tema
     escuro deixaria de ser. */
  /* 2026-08-21 — os quatro descem meio tom para o registro do pigmento:
     ouro-ouropigmento, verdete, laca de quermes, azurita. É a mesma família
     de matiz de sempre, com menos croma de papelaria e mais de manuscrito.

     **O NOME é contrato de dado, e por isso a matiz se move dentro da
     família em vez de trocar de família.** `roxo`, `amarelo`, `rosa` e
     `azul` são valores PERSISTIDOS: a API os valida
     (`api/leitor-api/lib/destaques.mjs`, `CORES` e as duas mensagens
     `cor-invalida`), grava `cor` com eles em cada destaque, e `corPadrao`
     das preferências guarda um deles (`lib/prefs.mjs`). Um `--hl-azul`
     violeta seria um nome mentindo sobre a cor; mudar o nome exigiria
     migrar destaque já gravado. Então a azurita continua azul, e a laca de
     quermes continua rosa.

     ── O roxo entrou e o verde saiu (2026-08-21) ─────────────────────────
     O roxo é a cor PADRÃO agora — `motor.mjs` declara `CORES` e
     `artigo.mjs` faz `corAtiva = CORES[0]`, então a primeira posição é o
     mecanismo inteiro; não há preferência gravada por trás.

     **Tirar o verde não custou migração, e isso foi medido, não suposto:**
     dos 158 destaques gravados, 156 são amarelo e 2 são rosa — verde e
     azul, zero. Nenhum destaque ficou órfão de token. Se algum verde
     existisse, ele cairia num `var(--hl-verde)` sem valor e apareceria
     sem marcação nenhuma; como não existe, o custo é zero. O azul ficou
     mesmo sem uso porque carrega o rótulo "Estrutural", que é o que
     conversa com a lente do arquiteto (03 §5.1).

     O roxo do escuro (`#42305c`) é o par mais apertado do arquivo, e a
     razão é nova: no tema escuro o ACENTO também é púrpura (`#c19ae6`), e
     `.prosa a` é destacável — um link roxo pode nascer por cima de uma
     marcação roxa. Medido em 4,99:1, dentro da faixa dos outros três
     (4,87–4,90). */
  --hl-roxo:    #d3bbe8;  --hl-amarelo: #eed88a;
  --hl-rosa:    #eeaebd;  --hl-azul:    #a6c3e4;

  --vivo-roxo:    #d3bbe8;  --vivo-amarelo: #eed88a;
  --vivo-rosa:    #eeaebd;  --vivo-azul:    #a6c3e4;

  /* `--raio` e `--raio-p` subiram ao núcleo (Task 9) com os mesmos valores —
     12px e 8px. A nuance de que dentro do texto não há superfície para
     arredondar (02 §9; o `4px` da imagem e do bloco de código não usa estes
     tokens de propósito) continua valendo, só que o token agora vem de fora. */

  /* ── Matiz por cluster  (02 §3.1) ────────────────────────────────────────
     Terceira família de cor deste arquivo, e a distinção contra as outras
     duas é a mesma de sempre — **camada e função**:

     | família | onde vive | muda com o tema? |
     |---|---|---|
     | `--hl-*`   | POR BAIXO do texto do artigo | sim, obrigatoriamente |
     | `--vivo-*` | amostra em botão e bolinha   | nunca |
     | `--t-*`    | identidade de um tema de estudo | só de valor, nunca de matiz |

     Duas regras governam os valores, e as duas são medidas em graus, não a
     olho:

     1. **O acento tem hue exclusivo.** Nenhum cluster fica a menos de ~50° do
        azul-noite (hue 216). Foi o que tirou `--t-arq` do azul-aço `#35618c`
        — 6° do acento, indistinguível numa bolinha de 7px — e o levou à
        ameixa, a 54°. Se um cluster ocupasse a matiz da marca, o chip ativo e
        o app diriam a mesma coisa em lugares diferentes, e o reconhecimento
        por cor (a razão inteira desta fileira existir) se dissolveria.
        Separações contra o acento: cyber 46°, arquitetura 54°, cristão 174°,
        cânone 130°, geral 120°. Entre clusters, o par mais próximo é
        cristão × cânone a 44° — âmbar e bordô, que saturação e brilho separam
        mesmo com a matiz vizinha.
     2. **Nome pela coisa, nunca pelo papel.** `--t-cyber`, e não `--t-1` nem
        `--t-primario`: um nome de papel deixa dois lados concordarem na
        palavra e discordarem na coisa.

     Quem escolhe a matiz de um cluster é `assets/matizes.mjs` — tabela para os
     conhecidos, hash do slug para o resto. Declarar o token aqui não põe cor
     em lugar nenhum: quem aplica é o `--t` inline do elemento. */
  /* 2026-08-21 — três dos cinco se mexeram, e a regra 1 acima é que mandou.
     Ela dizia "≥50° do azul-noite (hue 216)" porque o acento era azul nos
     TRÊS temas. Agora o acento é vermelho no claro (357), carmesim no
     sépia (344) e púrpura no escuro (271) — a regra continua a mesma, mas
     a zona proibida virou a UNIÃO de duas: [294°,47°] e [221°,321°]. Sobra
     a faixa livre [47°,221°], e é dentro dela que os cinco moram agora.

     Quem tinha de sair, e por quê:
     - `--t-canone` era bordô (#8c3b4e, hue 347). Ficava a 10° do acento
       vermelho: o chip do cânone e a marca do app diriam a mesma coisa em
       lugares diferentes, que é exatamente o que a regra 1 existe para
       impedir. Foi para o **louro** (hue 120) — a coroa de louro do poeta,
       que é o emblema do cânone desde antes de haver cânone.
     - `--t-arq` era ameixa (#6b4a8c, hue 268). Ficava a 3° do acento
       púrpura do escuro — pior colisão do conjunto, e invisível no claro,
       onde ninguém a veria acontecer. **Voltou ao azul-aço `#35618c`**, o
       valor que a rodada de 2026-08-02 tinha rejeitado por estar a 6° do
       acento de então. A razão que o expulsou era o acento ser azul; o
       acento deixou de ser azul, e o valor voltou a estar livre. Ajustado
       de 210° para 216° só para abrir o vão contra `--t-cyber`.
     - `--t-cristao` era âmbar-terra (#8a5a2b, hue 30), dentro da zona
       proibida do vermelho por 17°. Subiu para o **ouro** (hue 47), a 50°
       do acento — o mínimo da regra, cumprido e não raspado.

     `--t-cyber` (petróleo, 170°) não mudou. `--t-geral` virou **grafite**,
     e essa é a única mudança que não foi a regra 1 que pediu: com quatro
     matizes numa faixa de 174°, o quinto hue apertaria todos os vãos. O
     `geral` é o balde do que não tem tema declarado (`protocolos` cai
     nele) — dizer isso com um neutro é mais verdadeiro do que com o oliva,
     e devolve espaço aos quatro que carregam identidade de verdade.

     Vãos entre as quatro matizes: 73° · 50° · 46°. O par mais próximo era
     44° antes desta rodada (cristão × cânone) e passou a 46° (cyber ×
     arq) — a separação melhorou, não piorou. Contra os acentos: ouro a
     50° do vermelho, azul-aço a 55° da púrpura. */
  /* 2026-09-01 — a brasa, e por que ela devolve quatro das cinco matizes.
     (Claude Design, «Leitor — rodada 1», prancha 1a.)

     A rodada acima trabalhou com um acento que **mudava de matiz entre
     temas** — 357° no claro, 344° no sépia, 271° no escuro. Era isso, e não
     a regra 1, que apertava tudo: com três acentos, a zona proibida é a
     UNIÃO de três bandas de ±50°, e sobra um corredor de 174° para caber
     cinco matizes. Foi o corredor, não o gosto, que expulsou a ameixa e o
     bordô — e o comentário acima registra as duas saídas medindo contra o
     acento do ESCURO, que é o detalhe fácil de perder ao reler.

     A brasa vale 17,3° no claro, 17,5° no sépia e 17,4° no escuro: uma
     matiz só, que muda de valor e nunca de matiz. A zona proibida volta a
     ser UMA banda — [327°,67°] — e o corredor livre passa de 174° para
     **260°**. Não é uma cor mais bonita; é a paleta deixando de precisar
     ser revalidada tema a tema.

     Com o corredor aberto, três voltam ao valor que já tinham sido:
     - `--t-arq` volta à **ameixa** `#6b4a8c` (270°). Ela só era proibida
       pelo acento púrpura do escuro, que deixou de existir: agora está a
       107° da brasa nos três temas.
     - `--t-canone` volta ao registro do **bordô**, agora magenta `#83306b`
       (317°), a 59,9° da brasa — o par mais apertado do conjunto, e ainda
       acima do mínimo de 50° da regra 1.
     - `--t-cristao` recebe o **azul-noite** `#33538f` (219°), a matiz que
       era do acento antes de tudo isto. Não foi jogada fora: mudou de posto.

     `--t-cyber` (petróleo, 170°) não mudou pela segunda rodada seguida.
     `--t-geral` sai do grafite e vai ao **oliva** `#5c6b52` (96°): o grafite
     existia para devolver espaço num corredor apertado, e o corredor deixou
     de ser apertado.

     Medido, nos TRÊS temas (o que antes só valia num):
       cyber 153,0° · cristão 158,2° · arq 107,3° · cânone 59,9° · geral 78,7°
     Pior caso do conjunto: 59,9°, contra 43,2° da rodada anterior. Menor vão
     entre temas: 47,3° (arq × cânone), contra 6,5° antes — aquele 6,5° não
     era defeito (o grafite tinha saturação 4,8%, e matiz não governa cinza),
     mas some junto. */
  --t-cyber: #2f6d63;  --t-arq:    #6b4a8c;  --t-cristao: #33538f;
  --t-canone: #83306b; --t-geral:  #5c6b52;

  /* ── A matiz CHEIA da capa: HISTÓRICO desde 02/09 ────────────────────────
     Estes cinco vestiam a capa da estante, e a razão continua verdadeira: os
     `--t-*` acima trocam de valor por tema porque precisam ser legíveis como
     ponto e como texto sobre `--papel`, e a capa não é nenhuma das duas coisas
     — é um CAMPO, com texto claro por cima. Medido na época: `#fdf6ef` sobre
     as matizes claras dá 5,33–7,54:1; sobre as claras do tema escuro, 2,28.

     O que mudou é que a capa deixou de ser a única cara do objeto. Com a
     lombada, o mesmo livro aparece nas duas vistas — de pé na prateleira,
     deitado na grade —, e **duas cores para o mesmo livro não é coleção, é
     coincidência**: na grade a capa saía num magenta claro e na prateleira num
     bordô fundo (relato do Yuri, 02/09, com as duas telas lado a lado).

     A cor do objeto passou a ser uma só, a `--lombada-*` logo abaixo. Estes
     ficam declarados como valor de reserva do `var()` da capa — uma obra sem
     `--lombada` (marcação antiga em cache) cai neles em vez de cair no cinza. */
  --t-cheio-cyber: #2f6d63;  --t-cheio-arq:    #6b4a8c;  --t-cheio-cristao: #33538f;
  --t-cheio-canone: #83306b; --t-cheio-geral:  #5c6b52;

  /* ── A LOMBADA da estante: a mesma matiz, no registro de tinta  (02/09) ───
     A estante deixou de ser uma grade de capas em campo cheio e passou a ser
     a lombada de pé numa prateleira — e a capa virou detalhe de foco, uma por
     tela, na coluna da direita.

     Cinco tintas fundas (L~20%, croma baixo) nas MESMAS matizes dos
     `--t-cheio-*` acima: magenta 317°, petróleo 170°, ameixa 270°, azul-noite
     219°, oliva 96°. Elas moram no `:root` e não num bloco de tema pela razão
     que o comentário de cima já fixa e que aqui fica ainda mais literal: um
     livro na prateleira não muda de cor quando se apaga a luz da sala.

     Medido, texto sobre as cinco: título `--sobre-lombada` dá 9,88–11,33:1; o
     autor, que é o mesmo branco esmaecido, foi de 60% para **65%** porque a
     60% o pior caso (petróleo) media 4,67:1 — passava o piso de 4.5 e raspava
     a mira de 4.7 da casa. A 65% o pior caso é 5,15:1. Texto miúdo não afrouxa
     piso por ser miúdo; ele sobe a opacidade.

     `--sobre-lombada` é cravado e não vem de `--sobre-acento`: é o papel da
     lombada, e tem de ser o MESMO sobre as cinco matizes — a mesma razão que o
     `#fdf6ef` da capa cega já registra dois blocos abaixo. */
  --lombada-canone: #4a2038; --lombada-cyber: #1f3d38; --lombada-arq: #3a2a4c;
  --lombada-cristao: #23304a; --lombada-geral: #333a2c;
  --sobre-lombada: #f2eae0;

  /* A sombra da lombada é PRÓPRIA, e não `--sombra-erguida`: aquela é de
     objeto pairando sobre a mesa (dois degraus, deslocamento negativo em X
     pela `--luz-x`), e um livro apoiado na tábua não paira — ele encosta. Y
     positivo, luz alta, uma camada só. */
  --sombra-lombada: 3px 8px 16px rgba(34,33,29,.26);

  /* A tábua da prateleira. Não é `--papel-elev-*`: aquilo é papel, e isto é
     madeira vista de canto — 9px de altura, o brilho de cima e a sombra
     projetada logo abaixo. Vive no `:root` pela mesma razão das lombadas. */
  --tabua-1: #d3cabb; --tabua-2: #b6ab97;
  /* ── A tábua MUDA por tema, e a lombada não  (visto na captura de 02/09) ──
     Parece contradizer a regra do parágrafo acima, e não contradiz — separa
     duas coisas que a palavra «objeto» juntava. O LIVRO é objeto: a série tem
     de ser reconhecível, e um livro não muda de cor quando se apaga a luz da
     sala. A tábua é o MÓVEL, e móvel em sala escura está na penumbra.

     Sem isto, no tema escuro a prateleira vira a coisa mais clara da tela —
     mais clara que os livros que ela sustenta —, e o olho vai para o suporte
     em vez de ir para o acervo. Foi o que a captura mostrou, e não havia
     medição que pegasse: contraste de superfície contra superfície não tem
     piso, tem juízo. */

  /* ── `--perigo`: quinta família de cor, e a razão de nascer é a revisão
     final medindo `#d1495b` cravado em nove lugares, 3,38–4,29:1 contra o
     fundo real — hex fixo é invisível para o harness de contraste, que lê
     TOKEN, não literal (`contraste.mjs:tokens`), então nada aqui tinha
     como reprovar sozinho antes de chegar ao aparelho.

     Claro e sépia dividem o mesmo valor — `--papel-elev` e `--regra` dos
     dois temas são vizinhos de arredondamento (mesma razão do núcleo ter
     unificado os dois), então a mesma cor passa nos dois com a mesma
     folga. Escurecido de `#d1495b` (L 55,3%) para `#b42e3f` (L 44,3%),
     mesmo hue/saturação — é vermelho mais fundo, não vermelho diferente.
     Isso resolve as quatro superfícies de TEXTO onde a revisão media
     abaixo de 4.5:1 (`#acoes .perigo` sobre `--papel-elev`: 4,29→6,07:1;
     `.redondo.excluir:hover` idem; `.aviso-excluir`, texto corrido, idem;
     `.destaque .x:hover` sobre `--regra`: 3,37→4,77:1) e a pior das duas
     superfícies "armadas", onde o texto some sobre o próprio fundo tingido
     de si mesmo (`.redondo.excluir.armado`: 3,58→4,88:1). Mirado ≥4.7:1 em
     toda superfície, não 4.5 raspado — a mesma folga que o núcleo já usa
     nos ajustes de `--tenue`.

     As duas superfícies que são só MARCA (o tingido de fundo de `.armada`/
     `.armado`, 14–16% de mix sobre `--papel-elev`) não têm piso próprio —
     não são a única pista de nada, o texto e a borda ao lado já carregam
     a informação — e viram token pela mesma razão de qualquer literal:
     consistência de tema, não uma medição que precisavam passar.

     2026-08-21 — o acento entrou no vermelho, e `--perigo` teve de se
     afastar. **A separação não é de matiz — é de profundidade e croma**,
     e a escolha foi forçada pela aritmética: `#b42e3f` já media 4,708:1
     no pior caso (`.destaque .x:hover` sobre `--regra`), ou seja, já
     estava no TETO de claridade que o piso de 4.5 permite. Clarear não
     era uma opção disponível; o que sobrava era croma.

     `#b81028` mantém a mesma profundidade e sobe a saturação de 59% para
     84% (croma 168 contra os 112 do acento). Contra o oxblood do acento
     — que é fundo, apagado e lido como TINTA — este é claro, quente e
     lido como ALARME. Os dois vizinhos de matiz, separados por tudo o
     mais.

     Efeito colateral, e favorável: toda medição do teste SOBE.
     `--papel-elev` 6,07→6,58:1 · `--regra` 4,77→5,17:1 · armado 14%
     4,71→5,14:1 · armada 16% 4,71→4,95:1. O pior caso saiu de raspar o
     piso (4,708) para 4,95. */
  --perigo: #b81028;
}

[data-entrelinha="compacta"] { --leading: 1.45; }
[data-entrelinha="normal"]   { --leading: 1.6; }
[data-entrelinha="arejada"]  { --leading: 1.75; }
[data-largura="estreita"] { --medida-base: 31em; }
[data-largura="media"]    { --medida-base: 34.5em; }
[data-largura="larga"]    { --medida-base: 38em; }
[data-fonte="literata"]     { --corpo: var(--serif); }
[data-fonte="source-serif"] { --corpo: var(--serif-leitura); }
[data-fonte="inter"]        { --corpo: var(--sans); }
[data-fonte="charter"]      { --corpo: var(--serif-charter); }

/* ── Espaçamento para dislexia  (Bloco J2, `data-espacamento`) ──────────────
   Zorzi et al., PNAS 2012: espaço extra entre as letras deu ~20% mais
   velocidade de leitura e METADE dos erros em crianças disléxicas — sem
   treino nenhum, só a tipografia mudando debaixo do mesmo texto. É o único
   ajuste deste arquivo com efeito medido em ensaio clínico, e é exatamente
   por isso que ele entra como OPÇÃO e não como padrão: o mesmo trabalho não
   achou ganho em leitor típico, e `normal` tem de continuar sendo byte a byte
   a tipografia que o Bloco B validou no iPad. Ajuste que ajuda um grupo e
   custa a todos os outros não vira padrão; vira interruptor.

   ── Os dois andam JUNTOS, e é aqui que se erra ─────────────────────────────
   Subir `letter-spacing` sozinho PIORA a leitura, e a razão é estrutural: as
   letras de duas palavras vizinhas passam a ficar tão distantes entre si
   quanto as letras de dentro de uma palavra, e a fronteira de palavra — que é
   o que o olho usa para segmentar a linha — deixa de existir. O que o ensaio
   mediu foi espaço extra COM a palavra ainda coesa. Daí `word-spacing` crescer
   3× o `letter-spacing`, e não o mesmo tanto: manter a razão entre os dois é o
   ganho; igualá-la seria trocar um problema de leitura por outro.

   ── A medida da coluna é compensada, e a conta está aqui ────────────────────
   A 02 §2.3 fixa 62–72 caracteres por linha, e o protótipo mediu o avanço
   médio do caractere em **0,486em** (é o que dá as três larguras declaradas
   acima: 31em≈65ch, 34.5em≈71ch, 38em≈78ch). Espaçar sem mexer na medida
   encolheria a linha em ~16% de caracteres — 71 viraria 60, ABAIXO do piso —,
   e o ajuste que existe para facilitar a leitura cobraria de volta em salto de
   linha o que deu em legibilidade de letra.

   O avanço por caractere com o espaçamento ligado:

     0,486em (base)
     + 0,06em            (letter-spacing, que incide em todo caractere)
     + 0,18em ÷ 5,96     (word-spacing, diluído pela palavra do português:
                          4,96 letras + 1 espaço = 5,96 caracteres — contado
                          em 2.990 palavras de prosa da própria spec, não
                          estimado)
     = 0,576em           →  fator 1,19

   `--fator-espaco` multiplica `--medida-base`, então a compensação alcança as
   três larguras sem repetir número nenhum, e uma quarta largura que nasça
   amanhã já nasce compensada. É a diferença entre um invariante e três
   constantes que por acaso combinam hoje. */
[data-espacamento="arejado"] { --fator-espaco: 1.19; }
[data-espacamento="arejado"] .prosa { letter-spacing: .06em; word-spacing: .18em; }
/* O bloco de código é a exceção, e não por gosto: dentro de `<pre>` o
   alinhamento de coluna carrega informação (saída de terminal, diff, tabela
   ASCII), e `word-spacing` desalinha tudo o que tem mais de um espaço seguido.
   `<code>` inline fica espaçado junto com a frase em que vive — ali não há
   coluna a preservar, e destoar do texto ao redor é que seria o defeito. */
[data-espacamento="arejado"] .prosa pre { letter-spacing: normal; word-spacing: normal; }

/* ── O acento é RUBRICA · CARMESIM · PÚRPURA  (02 §3, direção Câmara) ───────
   2026-08-21 — o azul-noite saiu. Ele fora fechado em 2026-08-02 contra
   índigo, ametista e verde-petróleo; a ametista `#6a3f86`/`#c294dd` que
   aquela rodada rejeitou é, com dois pontos de diferença, o que hoje veste o
   tema escuro. Os rejeitados de então ficam registrados, agora como
   histórico e não como alternativa viva: índigo `#3f3d8f`/`#9a97e0`,
   petróleo `#2f6d63`/`#6fb3a5`, azul-noite `#26436e`/`#8fb3dd`.

   A cor nova é a do ofício que dá nome à fundação (ver a nota de paleta em
   `nucleo.css`): a **rubrica** do escriba no claro, o **carmesim** de
   quermes no sépia, a **púrpura** do codex purpureus no escuro. O valor é o
   mesmo de `--foco` do núcleo nos três temas — dois tokens, um valor,
   porque no Leitor o anel de foco e o acento do app são a mesma cor da casa
   e sempre foram (antes disto eram `#2b4c85` e `#26436e`, vizinhos de
   arredondamento fingindo ser dois).

   **O acento não colide com o rosa de destaque**, e a razão não é a matiz —
   as duas são avermelhadas. É a função e a saturação: o destaque é um
   pigmento dessaturado que vive POR BAIXO do texto; o acento é um tom fundo
   e saturado que vive no cromo. Nunca aparecem na mesma camada — e há teste
   que mede `--acento` sobre os quatro `--hl-*` justamente porque `.prosa a`
   pode receber marcação por baixo (medido: 4,96–6,43:1 no claro).

   A tensão papel quente × acento fundo continua deliberada: é ela que faz o
   acento parecer tinta sobre papel em vez de interface colorida.

   **`--sobre-acento` não é cosmético — é conserto de defeito.** O botão
   primário escrevia `#fff` sobre `var(--acento)`, e no tema escuro o acento é
   **claro**: dava ~2:1. O token existe para que ninguém volte a assumir
   branco, e há teste que falha se alguém voltar.

   **`--tenue` é informação, não decoração**: ele carrega a linha de crédito
   do item (fonte · minutos · data) e o rótulo da barra de navegação. Por isso
   responde ao 4.5:1 como qualquer outro texto — contra ~6.8:1 do `--tinta-2`.
   Um terceiro cinza "decorativo" a 3:1 é o defeito que a primeira versão dos
   mockups tinha.

   **O valor do escuro diverge do mockup, e a divergência é medida.** Lá o
   `--tenue` era `#83807b`, verificado contra `--papel` — e passava, com 4.56:1.
   Mas neste app ele mora **dentro do cartão**, sobre `--papel-elev`, que no tema
   escuro é MAIS CLARO que o papel: ali o mesmo valor caía para **4.19:1**. O
   mockup não pegou porque a tela onde o crédito do item aparece é a única em
   que o fundo dele não é `--papel`. Corrigido para `#8b8883` (bg 5.08:1, elev
   4.67:1), e há teste que confere as duas superfícies. */
/* ── O acompanhamento da voz saiu do `--acento`  (2026-08-26) ───────────────
   Até aqui as duas regras de `::highlight()` — a faixa da frase e a palavra
   corrente, lá embaixo — pintavam com `var(--acento)`. O empréstimo passou
   despercebido por meses porque o acento era vermelho no claro e no sépia
   enquanto o pigmento padrão do marca-texto é roxo: duas famílias de matiz,
   nenhuma colisão possível. Em 21/08 o acento do escuro virou púrpura, e o
   acompanhamento foi junto — **três coisas na mesma família** naquele tema
   (destaque `#42305c`, faixa de parágrafo e palavra), sem pista de cor para
   separá-las.

   O que fecha a questão é que **contraste nunca foi a pergunta ali**. Púrpura
   clara sobre púrpura escura mede 4,9:1 — passa todos os pisos deste arquivo,
   com folga, e ainda assim confunde. O que colidiu foi a MATIZ, e nenhum
   teste media matiz entre estas duas famílias. Por isso o conserto tem duas
   metades: os tokens abaixo, e um guarda de matiz em `bimodal-css.test.mjs`.

   `--acento` é cor de CROMO — link, botão primário, chip ativo, aba corrente,
   anel de foco, 65 usos neste arquivo. O acompanhamento é cor da CAMADA DE
   LEITURA, e divide superfície com o marca-texto. São perguntas diferentes, e
   um token só não podia responder às duas sem que a resposta de uma amarrasse
   a outra: mexer no acompanhamento do escuro exigiria repintar o app inteiro.

   ── Quem é âncora e quem carrega a identidade do tema ─────────────────────
   A divisão de papéis foi decidida junto, e ela é o que impede a colisão de
   voltar sob outro nome: **o marca-texto é a âncora** — fica na família
   amarela nos três temas, com o valor por tema que ele já tinha
   (`#eed88a` · `#ecd07a` · `#463911`, hue 45–47°, ver `--hl-amarelo`) — e **o
   acompanhamento é o que muda**, uma cor por tema. O padrão voltou a ser o
   amarelo em `motor.mjs` (`CORES[0]`) pela mesma decisão; a nota de lá conta o
   resto.

   ── A voz é ACROMÁTICA, e isso foi validado no olho, não deduzido ──────────
   As três cores foram escolhidas por Yuri numa página de amostras que punha
   nove candidatas sobre o papel de cada tema, com os três níveis na mesma
   frase (`C02 Claude/Output/2026-08-26 — Leitor — acompanhamento de
   leitura`). Havia saturadas na mesa em todos os temas — carmesim, verdete,
   azul-noite —, e as três escolhidas são **neutras**. Vale escrever a regra
   que saiu daí, porque ela é melhor do que a que entrou:

   **A camada de leitura tem uma cor só, e ela é do marca-texto.** O amarelo é
   o único pigmento saturado que a página recebe; a voz passando é um VÉU
   acromático. Isso dá ao olho um critério que não depende de comparar matiz —
   o que tem cor é decisão que fica, o que é cinza é a voz que passa —, e é
   uma distinção mais forte do que "amarelo contra verde", porque sobrevive a
   quem enxerga cor de outro jeito.

   O corolário derrubou a primeira escolha desta rodada, e fica registrado: com
   a âncora amarela, **o acompanhamento não podia ser dourado**. O ouro de
   iluminura `#d8b25a` (hue 41,9°) foi escolhido enquanto a âncora ainda era o
   roxo, e mede 3,4° do ocre `#463911` do escuro — a mesma colisão de hoje,
   trocada de família. Caiu antes de existir.

   Um valor por tema. São três cinzas, e cada um pende para um lado diferente:
   · claro  `#454a52` — ardósia de lápide, 8,41:1 contra o papel, croma 5%.
     Pende para o frio sobre papel quente. Aqui o acento (a rubrica `#8c1c22`)
     já é o vermelho da casa: uma segunda cor saturada brigaria com ele.
   · sépia  `#4a3f52` — ardósia arroxeada, 8,18:1, croma 7,5%. É o cinza que
     pende para a púrpura, e sobre papel rosa-velho ele lê como sombra do
     próprio papel. O carmesim `#8e1233` estava na mesa e foi visto lado a
     lado: perdeu por ser um segundo vermelho numa página que já tem o acento
     em carmesim.
   · escuro `#b0aca2` — cinza-osso, 7,91:1, croma 5,5%. O único que pende para
     o quente, e sobre papel frio é isso que o separa. Atenção para quem for
     medir: a matiz nominal dele é 43°, a **2,4° do ocre** do marca-texto — a
     separação aqui não é de matiz, é de CROMA (5,5% contra 21%) e de valor. O
     guarda em `bimodal-css.test.mjs` sabe disso e mede as duas coisas.

   ── `--leitura-forca`, e a outra metade do "difícil diferenciar" ───────────
   A faixa da frase é a cor da palavra enfraquecida, e a força era **12%
   cravada nos três temas**. Sobre `#16171a` isso dá 1,25:1 de uma cor clara
   sobre fundo quase preto — piso de 1,2:1 raspado, véu nenhum. Era a parte do
   defeito que não tinha nada a ver com matiz: no escuro a faixa mal existia, e
   o que sobrava para o olho eram duas coisas roxas em vez de três níveis.
   **20%** devolve 1,46:1 ali.

   Os temas claros também subiram, e por uma razão que só apareceu ao medir as
   cores escolhidas: com os cinzas, 12% valia 1,209:1 no claro e **1,205:1 no
   sépia** — acima do piso pelo terceiro decimal, que neste projeto conta como
   reprovado (a mesma régua que reprovou o `--tenue` do núcleo por 0,22% de
   margem). **14%** devolve 1,245:1 e 1,253:1, sem tocar em cor nenhuma: a
   folga se compra na força, que é o parâmetro que não foi validado no olho.
   O vermelho antigo tinha 1,232:1 no claro e não sofria disso — cinza a igual
   alpha rende menos contraste que pigmento, e é a conta que a troca de paleta
   trouxe junto.

   Nada disto é novo neste arquivo: `--hl-fantasma` faz o movimento idêntico e
   pela mesma razão (22% no claro e no sépia, 48% no escuro — ver a nota dele
   adiante). A força virou token pelo mesmo motivo pelo qual a cor virou: um
   literal na regra obriga os três temas a concordarem num número que só serve
   a um. */
/* ── `--foco` é declarado AQUI, e essa é uma fronteira nova  (2026-09-01) ────
   O token mora no `nucleo.css`, que é do Scriptorium e vale para os quatro
   apps — e lá ele valia exatamente os hex do acento do Leitor, porque o anel
   de foco e o cromo sempre foram a mesma cor nesta pele.

   Com a brasa isso deixa de ser verdade sozinho: mover `--acento` sem mover
   `--foco` deixaria um anel carmim em volta de um botão brasa. E mover
   `--foco` no núcleo alcançaria Tabula, Codex e Memoria — os dois últimos
   nem declaram acento próprio, eles pintam TEXTO com `--foco`, e o README do
   Scriptorium avisa que trocá-lo olhando só o teste de lá "passa verde e
   quebra dois apps".

   Então a pele redeclara o token para si. O núcleo não se toca, e o piso de
   3:1 como anel que `nucleo.test.mjs` mede continua medido lá — aqui a brasa
   passa com folga nos três temas (8,33 / 7,82 / 8,46 contra o papel). */
[data-tema="claro"]  { --acento:#832f0d; --sobre-acento:#ffffff; --foco:#832f0d;
  /* ── As duas bordas FINAS da rodada «grafite, lombada, prateleira» ────────
     `--papel-borda-fina` é o contorno de uma superfície que já se separa da
     mesa pela SOMBRA — cartão da lista, cartão do destaque, a caixa da busca,
     a cápsula flutuante. Ele não responde ao piso de 3:1 e não deve: o piso é
     para borda que é a ÚNICA pista de controle, e em nenhum destes ela é (a
     sombra é a pista; no cartão, a lombada também).

     `--aro-fino` é o aro do controle secundário — os círculos de ação de 29px
     no cartão e os de 34px na coluna da capa, e o chip de tema em repouso.
     Mesma dispensa e mesma razão: o glifo do círculo é `--tenue` (4,5:1+) e o
     chip carrega ponto colorido e rótulo. Onde a borda for tudo o que há, o
     token continua sendo `--borda-controle`, que é o que tem piso medido. */
  --papel-borda-fina: rgba(34,33,29,.07); --aro-fino: rgba(34,33,29,.15);
  /* ── A pele redeclara o grafite, e por que ela pode  (02/09) ──────────────
     Os `--cromo-*` do núcleo são os valores do tema claro, e é ele quem manda:
     o cromo não muda por tema (a nota no `nucleo.css` diz por quê). Os dois
     ajustes abaixo não desfazem isso — são o mesmo grafite deslocado um ponto,
     e existem por razões locais desta pele.

     Fica em TOKEN e não num `background` literal por dentro da media query
     porque o harness de contraste lê token, nunca literal: um gradiente
     cravado em regra é uma superfície que nenhum teste consegue medir, e a
     bateria de `cromo.test.mjs` precisa dos três temas. Mesmo movimento que
     `--foco` fez em 2026-09-01, e pela mesma razão. */
  --hl-fantasma: 22%;
  --leitura:#454a52; --sobre-leitura:#ffffff; --leitura-forca: 14%;
  --progresso:#26436e; }
[data-tema="sepia"]  { --acento:#7c2c0b; --sobre-acento:#ffffff; --foco:#7c2c0b;
  --papel-borda-fina: rgba(46,37,25,.07); --aro-fino: rgba(46,37,25,.16);
  /* Um ponto mais quente, para o grafite não brigar com o papel rosado. */
  --cromo-1:#2a2b2c; --cromo-2:#1e1d1d;
  /* Um passo mais quente, como o resto do sépia. */
  --tabua-1: #d6c8b2; --tabua-2: #b9a88e;
  --hl-fantasma: 22%;
  --leitura:#4a3f52; --sobre-leitura:#ffffff; --leitura-forca: 14%;
  --progresso:#2b4468;
  /* ── O amarelo do sépia é próprio, e foi o papel quente que obrigou ───────
     O `#f7e08a` que o claro usa ficava a **1.188:1** contra o papel novo
     (`#f8f3e9`) — abaixo do piso de 1.2:1 que a §5.1 registra, e o teste
     reprovou na hora. Não é caso de afrouxar o piso: um destaque que se
     confunde com a página é um destaque que não se acha ao reler, e o piso
     existe porque isso já aconteceu.

     Amarelo sobre papel amarelado é o par mais apertado que existe aqui, e ele
     já era o mais apertado no papel antigo (1.220:1). Esta é a variante por
     tema que a §5.1 sempre previu, aplicada onde a aritmética a exigiu:
     `#f2d36c` dá 1.327:1 contra a página e 11.56:1 de texto por cima.

     As outras três não precisaram: verde 1.41, rosa 1.61, azul 1.57. E
     `--vivo-amarelo` **não** muda — a amostra do botão precisa ser a mesma
     bolinha em todo tema, senão "a amarela" deixa de ser uma coisa só.

     2026-08-21 — reajustado para `#ecd07a` junto com a descida dos quatro ao
     registro do pigmento (ver `:root`): contra o papel do sépia dá 1,31:1,
     e o texto por cima segue em 10,10:1. */
  --hl-amarelo: #ecd07a;
}

/* ── O tema escuro precisa de OUTRA cor, não da mesma esmaecida ────────────
   Um pastel claro por baixo de texto claro é ilegível por construção, e
   esmaecer o `<mark>` inteiro só piora: `opacity` no elemento apaga o texto
   junto com o fundo. A saída é a que a §5.1 sempre pediu — **variante por
   tema**: no escuro, a mesma matiz vira um tom fundo e saturado, sobre o qual
   o texto claro do tema segue acima de 4.5:1, medido cor a cor.

   As matizes continuam distinguíveis entre si, que é o que faz a semântica das
   quatro cores (importante / vale citar / suspeito / estrutural) sobreviver. */
[data-tema="escuro"] {
  --acento:#f39d7a;
  /* Aqui o acento é CLARO. Branco por cima dele daria ~2:1 — quem escreve
     sobre o acento pergunta ao token, e o token responde com o papel. */
  --sobre-acento:#16171a;
  /* Mesma razão do bloco claro: a pele redeclara `--foco` para não deixar o
     anel numa cor e o cromo em outra. Ver a nota lá em cima. */
  --foco:#f39d7a;
  --papel-borda-fina: rgba(255,255,255,.06); --aro-fino: rgba(255,255,255,.16);
  /* Aqui a razão NÃO é cosmética: a mesa do escuro é `#14171a`, e o cromo tem
     de ficar um degrau mais CLARO que ela. Uma lateral mais funda que a mesa
     deixa de ser objeto pousado e vira buraco na tela. A borda também sobe um
     ponto, pelo mesmo motivo: sobre fundo escuro, .07 de branco some. */
  --cromo-1:#23282d; --cromo-2:#191c20; --cromo-borda:rgba(255,255,255,.08);
  /* A madeira na penumbra — ver a nota da tábua no `:root`. */
  --tabua-1: #3a3f45; --tabua-2: #262a30;
  /* O tema que obrigou a família a nascer — história e medições na nota
     "── O acompanhamento da voz saiu do `--acento`" acima. O cinza-osso é
     claro como o acento, então quem escreve por cima responde igual: o papel. */
  --leitura:#b0aca2; --sobre-leitura:#16171a; --leitura-forca: 20%;
  --progresso:#8fb3dd;
  /* Escurecidos nesta rodada (Onda 3, §4): o guarda de contraste que só
     testava `--tinta` sobre `--hl-*` ganhou `--acento` (`.prosa a` também
     é destacável — mesmo mecanismo, mesmo risco) e `--acento` claro sobre
     estes quatro fundos escuros dava 3,98–4,24:1, abaixo do piso. O
     conserto é aqui, não em `--acento`: o token do acento é usado em
     dezenas de outras superfícies já medidas e passando (links fora do
     destaque, chips ativos, foco), e mexer nele reabriria toda essa
     medição por um problema que só existe embaixo de quatro cores
     específicas. `--tinta` tinha folga de sobra para ceder (6,7–7,1:1
     antes de escurecer, ver `nucleo.test.mjs`) — escurecer o hl não a
     derruba, só cresce a margem. Mirado ≥4.7:1 contra `--acento`,
     preservando ≥4.5:1 contra `--tinta`: amarelo 3,98→4,82:1 (tinta
     6,69→8,09:1), verde 4,22→4,79:1 (tinta 7,09→8,04:1), rosa 4,16→4,80:1
     (tinta 6,98→8,06:1), azul 4,24→4,72:1 (tinta 7,13→7,92:1).

     2026-08-21 — os quatro descem mais um passo, pela MESMA aritmética e por
     um motivo novo: o acento deixou de ser o azul claro `#8fb3dd` e virou a
     púrpura `#c19ae6`, que é mais clara, e por isso mais apertada por cima
     de um fundo escuro. Com os valores da Onda 3 o par `--acento` × `--hl-*`
     media 4,59–4,70:1 — passava o piso de 4.5 raspando, sem a folga que este
     projeto exige. Escurecidos para mirar ≥4,8:1 contra o acento: amarelo
     4,64→4,87 · verde 4,62→4,82 · rosa 4,70→4,90 · azul 4,59→4,88. O par
     contra `--tinta` só cresce (8,66–8,81:1). */
  --hl-roxo:    #42305c;  --hl-amarelo: #463911;
  --hl-rosa:    #632439;  --hl-azul:    #1f3c5a;
  /* As matizes de cluster trocam de VALOR, nunca de matiz: no escuro elas
     precisam ser claras para continuarem legíveis sobre `--papel`, e continuam
     sendo a mesma cor do mesmo tema de estudo.

     2026-09-01 — refeitas junto com as claras (ver o bloco da brasa em
     `:root`). Cada uma é a matiz NOVA no mesmo registro de L e S que a irmã
     escura tinha antes: a regra deste bloco é "troca de valor, nunca de
     matiz", e mover a matiz em cima sem mover aqui embaixo a quebraria — foi
     exatamente o que o teste «NENHUM CLUSTER OCUPA A MATIZ DO ACENTO» pegou,
     com `--t-cristao` a 25° da brasa no escuro enquanto a versão clara já
     estava a 158°.

     A exceção é `--t-cristao`, que precisou subir de L 56,5% para 67%: no
     azul-noite o valor herdado dava 4,42:1 contra `--papel`, fora do registro
     dos irmãos (6,05–8,89). A 67% dá 6,57:1 e volta para dentro da família.

     Contraste sobre `--papel` (#16171a): cyber 6,06 · arq 6,37 ·
     cristão 6,57 · cânone 6,67 · geral 7,34. */
  --t-cyber: #5fa297;  --t-arq:    #b585e6;  --t-cristao: #7d9dd9;
  --t-canone: #c48db4; --t-geral:  #a1a89d;
  /* O fantasma do ajuste precisa de mais força aqui: 22% de um tom já escuro,
     sobre fundo escuro, some. */
  --hl-fantasma: 48%;
  /* Medido depois de escurecer os quatro `--hl-*` acima (Onda 3, correção):
     o fantasma (48% de mistura sobre `--papel`) não foi remedido junto, e a
     razão contra a página caiu de 1,310–1,351 (hl-* antigo) para
     1,240–1,260 (amarelo 1,253 / verde 1,258 / rosa 1,240 / azul 1,260) —
     ainda acima do piso de 1,2:1 que a 03-destaques §5.1 registra, mas com
     folga de 3–5% em vez dos 9–12% de antes.

     Decisão: não mexer. A diferença para o caso do `--tenue` (nucleo.css,
     onde 0,22–0,7% de folga foi tratado como reprovação) é dupla: 1,2:1 é
     um piso DESTE projeto para a identificabilidade da marcação — não é o
     piso normativo de texto da WCAG que o `--tenue` precisa cumprir sem
     alternativa —, e o fantasma nunca é a ÚNICA pista: `.editando` sempre
     vem com `outline: 1px dashed var(--acento)` ao lado (duas regras
     abaixo), que não depende desta cor nem deste contraste para marcar onde
     o destaque em ajuste começa e termina. O `--tenue` carrega informação
     sozinho, em texto lido a todo momento; o fantasma é um estado
     transitório — só existe enquanto o dedo arrasta uma alça — e tem reforço
     redundante ao lado. A mesma folga apertada que era risco real num é
     folga suficiente no outro. */
  /* --perigo clareia no escuro, mesma lógica de `--acento`: o fundo é que
     ficou escuro, então quem carrega a cor de perigo precisa ficar clara
     para continuar lendo acima do piso — vermelho profundo sobre fundo
     quase preto é a MESMA aritmética que branco sobre acento, invertida.
     `#e08692`, mesmo hue/saturação do claro, L 70,3%. Sobre `--papel-elev`
     escuro dá 6,28:1 (era 3,78); sobre `--regra` escuro (hover do ✕ de
     `.destaque`) 5,10:1 (era 3,07 — o pior caso do tema, por isso decide o
     valor); sobre o próprio fundo "armado" (tingido de si mesmo a 14–16%)
     4,84–5,02:1 (era 3,22–3,30 — correção: o relatório anterior citava
     3,30–3,58, que troca o pior caso do escuro por 3,58, o pior caso do
     CLARO; o par certo do escuro antigo é 3,22–3,30).

     2026-08-21 — `#f27f92`, um passo mais claro e mais saturado, acompanhando
     o `#b81028` do claro. Aqui não havia colisão a resolver (o acento do
     escuro é púrpura), mas a cor de perigo é uma só ideia nos três temas e
     não faria sentido ficar dois passos atrás no escuro. Todas as medições
     sobem: `--papel-elev` 6,28→6,46:1 · `--regra` 5,10→5,25:1 · armado
     14–16% 4,84–5,02→4,97–5,16:1. */
  --perigo: #f27f92;
}

/* O reset (box-sizing, -webkit-text-size-adjust, margin/font-smoothing do
   body) e o `@media (prefers-reduced-motion)` subiram ao núcleo (Task 9). O
   que fica é só o que é do Leitor: papel/tinta vêm do tema, e a tipografia de
   leitura (`--corpo`, `--size`, `--leading`) não existe na fundação.

   ── `--tela`, não `--papel` (Onda 3) ────────────────────────────────────
   O corpo é a MESA, não a folha — é o que faz o claro do Leitor bater com o
   claro do Tabula (os dois são vistas do mesmo mundo: papel sobre
   escrivaninha). A folha ganhou existência própria em `.artigo` (ver
   comentário lá): só a tela de leitura tem folha, então só ela pinta
   `--papel`; toda superfície de serviço (inbox, destaques, busca, entrada)
   fica direto sobre a mesa, como sempre foi visualmente — a diferença é
   que agora a mesa tem um token que é dela, e não emprestado do papel. */
body {
  background: var(--tela); color: var(--tinta);
  font-family: var(--corpo); font-size: var(--size); line-height: var(--leading);
  transition: background-color var(--dur) var(--curva), color var(--dur) var(--curva);
}

/* ═══════════════════════════════════════════════════════════════════════════
   CROMO GLOBAL — cabeçalho que rola, navegação embaixo  (L-66, 02 §4, D1)
   ═══════════════════════════════════════════════════════════════════════════
   O `#topo` fixo de 52px saiu. Duas razões, e a segunda é a que decide:

   1. O alcance do polegar em retrato e do dedo apoiado em paisagem está
      **embaixo**. Uma navegação no alto do iPad é uma navegação que se alcança
      levantando a mão do aparelho.
   2. O alto da tela é onde o olho **começa a ler**. O cabeçalho fixo cobrava
      aquela faixa em toda leitura, com `backdrop-filter` permanente por cima
      do texto — e o blur estava ali para disfarçar o que ele mesmo criava.

   No lugar dele, duas peças com papéis distintos:

   - `.cabeca` — **no fluxo**, rola com o conteúdo e some sozinha. Leva a
     identidade do app e os dois controles que não são navegação (`Aa` e sair).
   - `#barra-nav` — fixa embaixo, em vidro, um destino por alvo de 52px.

   **A barra some pelo mesmo `data-cromo` que escondia o `#topo`** — não por um
   mecanismo novo. É o que mantém vivo o gesto da L-53b (tocar no texto traz o
   cromo de volta): ele mexe num atributo do `<body>`, e continua mexendo no
   mesmo. Inventar um segundo caminho aqui seria criar dois donos para "o cromo
   está visível?", que é como um deles fica para trás. E some **só na tela de
   artigo** — a regra é `body[data-leitura][data-cromo="oculto"]`, ver a
   seção do cromo adiante.
   ─────────────────────────────────────────────────────────────────────────── */

/* Altura reservada embaixo. Um token porque três coisas dependem dela — o
   fim do `main`, o botão da caneta e o aviso de diagnóstico —, e uma altura
   copiada em três lugares é uma altura que desalinha na primeira mudança. */
:root { --barra-h: calc(58px + env(safe-area-inset-bottom)); }

/* ── A base da coluna flutuante  (spec 14 §4.1) ─────────────────────────────
   A pílula do tempo mora ABAIXO da caneta, e abaixo da caneta não havia lugar:
   ela estava a 1rem da barra de navegação, e as duas aparecem no MESMO
   instante — o cromo visível mostra as duas ou esconde as duas. A faixa teve
   de ser aberta.

   `--tempo-h` é reservado SEMPRE, com pílula ou sem. Sem isso a caneta subiria
   e desceria a cada rolagem, e **controle que salta é pior que controle
   deslocado**: o polegar aprende uma posição, não uma fórmula. O custo é uma
   mudança única e permanente de ~28px, e o que a 02 §4 exige da caneta —
   "acima da barra inferior, para o dedo não acertar Destaques" — continua
   valendo com folga. */
/* `--bolha`/`--bolha-folga` (Bloco J4): a coluna nasceu com uma bolha e chegou
   a três, e cada degrau repetia "56px + .7rem" escrito à mão. Um número solto
   num degrau desalinha a coluna inteira em silêncio — nada quebra, os botões
   só deixam de se encaixar. */
:root {
  --tempo-h: 26px; --pilha-base: calc(var(--barra-h) + 1rem);
  /* 48px desde 01/09 (era 56). A coluna voltou a ter as SETE bolhas depois do
     rollback da gaveta, e sete de 56px cobrem o fim de muita linha no iPhone —
     foi o que fez a gaveta parecer necessária. Encolher 8px devolve ~15% da
     coluna sem tirar nada da tela, e 48 continua acima do `--alvo` de 44px que
     o núcleo exige de qualquer toque. Escolha de Yuri vendo as três medidas.

     Quem depende deste número: o `--degrau` abaixo (e portanto as sete
     posições), o recuo do `#velocidade-painel` e do painel de ajustes, e o
     corpo de texto das duas bolhas que carregam TEXTO em vez de glifo — a do
     progresso e a da velocidade, ambas ajustadas junto. */
  --bolha: 48px; --bolha-folga: .7rem;
  /* O DEGRAU da coluna — bolha mais folga, uma vez só. A coluna chegou a cinco
     bolhas no Bloco J7, e a corrente escrita à mão em cada uma já vinha
     repetindo "+ var(--bolha) + var(--bolha-folga)" quatro vezes na mais alta.
     Com o degrau, cada bolha declara a POSIÇÃO dela (`* 2`, `* 3`) em vez de
     recontar a coluna inteira, e mudar o diâmetro continua movendo as cinco
     juntas. */
  --degrau: calc(var(--bolha) + var(--bolha-folga));
  /* O primeiro degrau: acima da barra e da faixa reservada da pílula do tempo.
     Ele é a base de TODAS as bolhas, e por isso tem nome. */
  --pilha-0: calc(var(--pilha-base) + var(--tempo-h) + .5rem);

  /* ── AS DUAS CÁPSULAS  (02/09) ───────────────────────────────────────────
     `--bolha` e `--degrau` continuam vivos acima: eles regiam SETE posições e
     agora regem a base da pilha e a folga da pílula do tempo. Apagá-los
     levaria junto o `#tempo-leitura`, que é o que a nota da spec 14 §4.1
     protege.

     A geometria das cápsulas é declarada, e não somada à mão em cada regra,
     por uma razão concreta: dois painéis se alinham a itens do MEIO da pilha
     (o deslizante da velocidade e o sumário), e uma altura escrita à mão em
     três lugares desalinha na primeira mudança. */
  --capsula-l: 52px;
  --capsula-item: 48px;
  --capsula-anel: 52px;
  --capsula-item-texto: 50px;
  --capsula-gap: 14px;
  --capsula-x: 22px;
  /* A altura do «Seguir» tem nome porque é lida em DOIS lugares: o botão, lá
     embaixo, e a conta que centra a pilha no Mac. Escrita à mão nos dois, a
     primeira mudança desalinha a coluna sem quebrar nada visível. */
  --capsula-seguir-h: calc(var(--capsula-item-texto) + 10px);
}

/* ── A geometria das TRÊS cápsulas mora TODA no `body`  (04/09) ────────────
   Em 03/09 esta seção aprendeu, por um defeito de 128px, que **um `var()` é
   substituído no elemento em que a variável é declarada**: escrita no `:root`,
   uma soma congela os valores do `:root` e desce como número pronto, e a rota
   que redeclara uma das parcelas no `body` chega depois da conta já feita.
   A regra que ficou foi «derivada de token que alguma rota redeclara mora no
   mesmo elemento em que a rota o redeclara» — e a rodada de 04/09 a levou até
   o fim: **as parcelas também**. Altura de cápsula e soma da coluna vivem
   ambas aqui, e a escrivaninha redeclara o que muda sem precisar refazer as
   somas à mão. Um lugar só para errar, em vez de três que têm de concordar.

   Os `+ 2px` de cada altura são os dois FIOS da borda da cápsula (1px em cima
   e embaixo). Sem eles a altura declarada fica 2px menor que a real por
   cápsula, e o centramento do Mac erra por metade da soma.

   `--voz-bloco` é a cápsula da voz **mais o gap acima dela**, e vale zero
   quando ela não existe: um artigo sem narração não tem `⏸`, não tem `1,0×` e
   não tem `⇕`, e a coluna é de duas peças. Quem acende o atributo é
   `ligarOuvir` — ver `artigo.mjs`. */
body {
  --capsula-pagina-h: calc(var(--capsula-anel) + var(--capsula-item) + 2px);
  --capsula-voz-h: calc(var(--capsula-item) * 3 + 2px);
  --capsula-mao-h: calc(var(--capsula-item-texto) * 3 + 2px);
  --voz-bloco: 0px;
  --pilha-h: calc(var(--capsula-pagina-h) + var(--capsula-gap)
    + var(--voz-bloco) + var(--capsula-mao-h));

  /* Onde a BASE da pilha pousa: no modo barra é acima da barra e da pílula do
     tempo, como sempre foi; no Mac ela se centra — e se centra pela base,
     porque é pela base que a coluna é ancorada. Depois do primeiro arrasto
     quem manda é o valor guardado, que `pilha.mjs` escreve inline aqui. */
  --pilha-y: var(--pilha-0);

  /* As alturas a partir da base da pilha, para os dois painéis que nascem de
     um item do meio: o sumário (do anel do progresso) e o deslizante da
     velocidade. O `Aa` é o item de BAIXO da cápsula da página, e o anel está
     um item acima dele; o `1,0×` é o do meio da voz, um item acima da base
     dela. */
  --y-aa: calc(var(--capsula-mao-h) + var(--capsula-gap) + var(--voz-bloco));
  --y-progresso: calc(var(--y-aa) + var(--capsula-item));
  --y-velocidade: calc(var(--capsula-mao-h) + var(--capsula-gap) + var(--capsula-item));
}
body[data-voz] { --voz-bloco: calc(var(--capsula-voz-h) + var(--capsula-gap)); }

@media (min-width: 1100px) and (pointer: fine) {
  body { --pilha-y: calc(50% - var(--pilha-h) / 2); }
}

/* ── O vermelho que se lê SOBRE o cromo  (04/09) ───────────────────────────
   Irmão do `--cromo-acento` do núcleo, e pela mesma razão registrada lá: o
   cromo não muda por tema, então a tinta que escreve sobre ele também não.
   `--perigo` é `#b81028` no claro — vermelho de papel, escuro sobre escuro
   assim que o botão que o usa passou a ter campo grafite. Este é o `--perigo`
   do tema ESCURO, servido nos três.

   Mora na pele e não no `nucleo.css` porque o núcleo é do Scriptorium: editar
   a cópia que vive dentro do app é perder a edição na próxima sincronização. */
:root { --cromo-perigo: #f27f92; }

/* ── A pilha e as três cápsulas ───────────────────────────────────────────
   `pointer-events: none` na coluna e `auto` nas cápsulas: a coluna é uma faixa
   de 52px de largura sobre o texto, e sem isto ela roubaria o toque da prosa
   nas margens do que ela mesma não desenha.

   `overflow: hidden` na cápsula é o que faz o raio de 26px cortar o primeiro e
   o último item — sem ele, o realce de hover do item do topo escapa pela
   quina arredondada.

   ── O CROMO desceu para cá  (04/09) ─────────────────────────────────────
   A cápsula era papel elevado sobre papel: uma pastilha clara sobre a folha
   clara, separada dela por um fio. Passou a ser **o mesmo material da lateral
   e da barra** — o gradiente `--cromo-1 → --cromo-2`, grafite nos três temas.
   É a decisão de 02/09 aplicada ao resto do app: a coluna flutuante não é
   página, é ferramenta, e ferramenta se distingue da página pelo material, não
   por um filete.

   Com o campo escuro vem o resto do pacote daquela decisão: a tinta é
   `--cromo-tinta-2`, o realce é `--cromo-acento` (o acento do tema ESCURO, em
   qualquer tema) e a divisória é `--cromo-borda`. Um acento claro sobre
   grafite reprovaria medido, e a regra da casa é clarear a TINTA, nunca o
   campo. */
#pilha-leitura {
  position: fixed; right: var(--capsula-x); bottom: var(--pilha-y);
  z-index: 46; pointer-events: none;
  display: flex; flex-direction: column; align-items: flex-end; gap: var(--capsula-gap);
}
.capsula {
  pointer-events: auto;
  width: var(--capsula-l); flex: none;
  display: flex; flex-direction: column;
  background: linear-gradient(180deg, var(--cromo-1), var(--cromo-2));
  border: 1px solid var(--cromo-borda);
  border-radius: 26px; box-shadow: var(--sombra-erguida); overflow: hidden;
  /* O arrasto da coluna (04/09): sem isto o Safari decide rolar a página no
     início do gesto, e o dedo que queria mover a pilha rola o artigo debaixo
     dela. A mesma armadilha do `touchstart` da caneta, e o mesmo remédio —
     dizer ao motor, ANTES do gesto, que esta superfície não é para rolar. */
  touch-action: none;
}
/* Enquanto a coluna está sendo arrastada, o cursor é o mesmo no documento
   inteiro: o ponteiro sai de cima da cápsula durante um gesto rápido, e um
   cursor que pisca entre a mão fechada e a seta faz o arrasto parecer ter
   terminado quando não terminou. */
body[data-arrastando-pilha] { cursor: grabbing; }
body[data-arrastando-pilha] .capsula > button { cursor: grabbing; }
/* A divisória entre itens, e o seletor merece nota: `:not([hidden]) ~
   :not([hidden])` dá a régua a todo item que tenha ALGUM irmão visível antes
   dele — que é exatamente «todos menos o primeiro visível». Com
   `:not(:first-child)` a régua nasceria no topo da cápsula sempre que o
   primeiro item estivesse escondido. */
.capsula > :not([hidden]) ~ :not([hidden]) {
  border-top: 1px solid var(--cromo-borda);
}
/* Uma cápsula sem nenhum item visível não pode desenhar uma pílula vazia.
   `:not(:has(...))` faz isso sem JavaScript, e o Safari o suporta desde 2023
   — se algum dia não suportar, o pior caso é uma pílula vazia, não um app
   quebrado.

   É esta regra que faz a cápsula da VOZ nascer inteira ou não nascer: os três
   itens dela seguem o mesmo sinal («este artigo tem narração?»), e quando ele
   é não, os três estão `hidden` e a peça se recolhe sozinha. */
.capsula:not(:has(> :not([hidden]))) { display: none; }
/* ── E fora da leitura a pilha INTEIRA não existe  (03/09) ─────────────────
   A regra acima testa o ATRIBUTO `hidden`. Só que, fora da leitura, os itens
   somem por `display: none` do CSS (`body:not([data-leitura]) …`), e um
   elemento assim continua casando com `:not([hidden])` — a cápsula
   sobrevivia ao teste e desenhava a si mesma sem nada dentro: uma pílula de
   52 px por 2, pairando sobre a inbox. «o que é essa barrinha branca?»

   Não dá para consertar isso alargando o `:has()`: CSS não pergunta pelo
   `display` computado de um filho. O conserto é dizer a verdade mais simples,
   que é a da rota — fora da leitura não há coluna nenhuma, e por isso ela não
   se desenha. A regra acima continua valendo DENTRO da leitura, onde a
   cápsula pode esvaziar por atributo. */
body:not([data-leitura]) #pilha-leitura { display: none; }
/* Os itens: mesma forma, alturas do desenho. Sem `border-radius` próprio (a
   cápsula corta), sem sombra (a cápsula tem a dela) e sem fundo (a cápsula é
   a superfície). É o que os faz parecer UMA peça em vez de três coladas. */
.capsula > button {
  width: var(--capsula-l); height: var(--capsula-item); min-height: 0;
  flex: none; border: 0; background: none; color: var(--cromo-tinta-2);
  display: grid; place-items: center; cursor: pointer; padding: 0;
  position: relative;
  appearance: none; -webkit-appearance: none;
  font-family: var(--sans); line-height: 1;
}
.capsula > button:hover, .capsula > button:focus-visible { color: var(--cromo-acento); }
#capsula-mao > button { height: var(--capsula-item-texto); }

/* ═══ A COLUNA NO TELEFONE: A BARRA DO RODAPÉ  (14/09) ═══════════════════════
   «Olha o tanto que a interface do Leitor está ruim no iPhone» — a captura
   (440 × 956) mostrava a coluna de três cápsulas em cima da prosa: 56 px de
   cada linha por 428 px de altura, e na tela do estudo, com cinco cápsulas,
   26 das 30 linhas da tela. No telefone não há margem ao lado da prosa para
   uma coluna, e estreitar a prosa para abrir uma seria piorar o que já é
   escasso.

   A forma é a do Codex («Ilhas no telefone», 14/09), de propósito a mesma:
   abaixo de 40rem (`TELEFONE` em `pilha.mjs`, que escreve `data-arranjo` no
   `<body>`), as cápsulas deitam numa fileira de borda a borda, colada em cima
   da barra de abas, no material dela, rolável na horizontal, com a pílula do
   tempo na ponta esquerda. As cápsulas viram GRUPOS — sem moldura própria,
   porque a barra é o fundo — separados por um fio. Nada muda de tamanho além
   do piso: todo item tem o `--alvo` de 44px. Na tela do estudo os itens não
   cabem na largura: os que passam ficam a um arrasto de lado, e a ordem põe
   a leitura primeiro (progresso, Aa, voz, mão), o estudo depois e a bancada
   por último.

   A barra NÃO segue o `data-cromo` — é o que o percentual exige («estou
   sentindo falta do percentual na tela», 01/09). Quando a barra de abas some
   ao rolar, esta desce ao chão com ela e passa a responder pela zona do
   indicador de início.

   Os seletores começam em `body[data-arranjo="barra"]` e por isso vencem as
   regras da coluna pela especificidade, não pela posição neste arquivo. */
body[data-arranjo="barra"] {
  /* A altura da fileira: o alvo mais o fio de cima. É o que a pílula do tempo,
     o fim do fluxo e os painéis ancorados na coluna precisam saber. */
  --fileira-h: calc(var(--alvo) + 1px);
  --pilha-y: calc(var(--barra-h) + var(--fileira-h));
  --pilha-0: calc(var(--pilha-y) + .5rem);
  /* Os painéis nasciam ao lado de itens do MEIO da coluna; deitada, todos os
     itens estão na mesma linha, e a âncora é a base da barra. */
  --y-aa: 0px; --y-progresso: 0px; --y-velocidade: 0px;
}
body[data-arranjo="barra"] #pilha-leitura {
  left: 0; right: 0; bottom: var(--barra-h);
  flex-direction: row; align-items: stretch; gap: 0;
  /* A ponta esquerda é da pílula do tempo, que é outra peça pendurada no
     corpo. */
  padding-inline: calc(env(safe-area-inset-left, 0px) + 3.6rem)
                  calc(env(safe-area-inset-right, 0px) + var(--alvo) + 1rem);
  overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
  /* Na coluna a faixa deixava o toque passar para a prosa; na barra não há
     prosa debaixo dela. */
  pointer-events: auto;
  background: linear-gradient(180deg, var(--cromo-1), var(--cromo-2));
  border-top: 1px solid var(--cromo-borda);
  transition: bottom var(--dur) var(--curva), padding-bottom var(--dur) var(--curva);
}
body[data-arranjo="barra"] #pilha-leitura::-webkit-scrollbar { display: none; }
/* A cápsula vira grupo: sem moldura própria (a barra É o fundo) e com
   `pan-x`, porque na coluna o `touch-action: none` existia para o arrasto
   vertical — aqui ele impediria o dedo de rolar a fileira. */
body[data-arranjo="barra"] .capsula {
  flex-direction: row; flex: none; width: auto; height: var(--alvo);
  background: none; border: 0; border-radius: 0; box-shadow: none; overflow: visible;
  touch-action: pan-x;
}
body[data-arranjo="barra"] .capsula ~ .capsula {
  margin-inline-start: .25rem; padding-inline-start: .25rem;
  border-inline-start: 1px solid var(--cromo-borda);
}
/* A régua entre itens era horizontal na coluna; deitada, não há régua. */
body[data-arranjo="barra"] .capsula > :not([hidden]) ~ :not([hidden]) { border-top: 0; }
/* `:is()` e não uma lista de seletores: o teste da bolha do progresso lê o
   PRIMEIRO `#progresso-flutuante {` do arquivo por regex, e uma lista aqui,
   antes da regra dela, seria o que ele encontraria. */
body[data-arranjo="barra"] :is(.capsula > button, #capsula-mao > button, #progresso-flutuante) {
  width: var(--alvo); height: var(--alvo);
}
/* Os dois botões que carregam TEXTO em vez de glifo crescem na largura. */
body[data-arranjo="barra"] #estudo-seguir,
body[data-arranjo="barra"] #bancada-face { width: auto; min-width: var(--alvo); padding: 4px 10px 5px; }
/* A leitura primeiro; o que a tela do estudo acrescenta vem depois, e a
   bancada por último — é o que fica a um arrasto de lado. */
body[data-arranjo="barra"] #capsula-pagina { order: 1; }
body[data-arranjo="barra"] #capsula-voz { order: 2; }
body[data-arranjo="barra"] #capsula-mao { order: 3; }
body[data-arranjo="barra"] #capsula-estudo { order: 4; }
body[data-arranjo="barra"] #capsula-bancada { order: 5; }
/* A pílula do tempo na ponta esquerda da barra, na tinta do cromo, mostrando
   só a sessão: «12 min». O acumulado é secundário por desenho, e na barra
   não há largura para dois números. */
body[data-arranjo="barra"] #tempo-leitura {
  left: calc(env(safe-area-inset-left, 0px) + .5rem); right: auto;
  bottom: var(--barra-h); z-index: 47;
  height: var(--alvo); padding: 0 .3rem;
  background: none; border: 0; box-shadow: none;
  color: var(--cromo-tinta-2); font-size: .72rem; font-weight: 600;
  transition: bottom var(--dur) var(--curva);
}
body[data-arranjo="barra"] #tempo-leitura :is(.sep, .total, .rot) { display: none; }
body[data-arranjo="barra"][data-cromo="oculto"] #tempo-leitura {
  opacity: 1; transform: none; bottom: env(safe-area-inset-bottom, 0px);
}
/* O fim do texto rola até acima das DUAS barras. */
body[data-arranjo="barra"] #versao { padding-bottom: calc(var(--pilha-y) + 1.5rem); }
/* Os painéis que nasciam à esquerda da coluna pousam acima da barra. */
body[data-arranjo="barra"] #velocidade-painel {
  right: .6rem; left: auto; bottom: calc(var(--pilha-y) + .5rem);
  width: min(20rem, calc(100vw - 1.2rem));
}
body[data-arranjo="barra"] #coloquio { right: .6rem; width: min(30rem, calc(100vw - 1.2rem)); }

/* ── UMA BARRA SÓ NO TELEFONE  (spec 63, 19/09) ──────────────────────────────
   «esses menus do leitor no iphone estão muito feios». Lendo, o rodapé tinha
   DUAS barras de grafite empilhadas — esta fileira e as abas —, ~170 px de
   cromo escuro sobre a página creme, com ícones de pesos diferentes e fios
   que não se alinhavam de uma barra para a outra.

   O dono escolheu o modelo do Books: lendo, a fileira toma o lugar das abas,
   que voltam pelo «≡» na ponta direita ou rolando para cima (`data-abas`,
   escrito por `ligarAbas` em `pilha.mjs`). O `data-cromo` deixa de mandar na
   fileira do telefone: ele mostra tudo perto do topo e a cada toque no texto,
   e a barra dupla voltaria justamente na abertura do artigo.

   E a barra veste o material da PÁGINA. Revoga, só no telefone, a regra de
   02/09 («a barra de baixo é o mesmo cromo da lateral»): lá a razão era a
   peça não mudar de material com a largura; aqui o dono pediu, olhando o
   aparelho, que ela deixe de ser um bloco preto sob o texto. O jeito é
   redeclarar os `--cromo-*` com escopo nas peças do rodapé — o anel, os
   ícones, o destino ativo e o ponto do boletim (spec 62) mudam juntos, sem
   uma regra por peça.

   O material é VIDRO: papel a 78% com desfoque, o texto passando borrado por
   baixo. Escolhido pelo dono na Mesa entre três (papel elevado, a cor da mesa
   e este), nos três temas, com capturas do simulador. */
body[data-arranjo="barra"] :is(#pilha-leitura, #barra-nav, #tempo-leitura, #abas-alternar) {
  --barra-fundo: color-mix(in srgb, var(--papel) 78%, transparent);
  --cromo-1: var(--barra-fundo); --cromo-2: var(--barra-fundo);
  /* O fio a 20% da tinta, e não a `--regra` da página: em sépia a régua é
     #e4d9cb sobre #f3e8da (~1,1:1) e no aparelho a barra ficou sem desenho
     nenhum («não tem divisória nem nada?»). Escolhido na Mesa entre a régua,
     20% e 30%, nos três temas. */
  --cromo-borda: color-mix(in srgb, var(--tinta) 20%, transparent);
  --cromo-tinta: var(--tinta); --cromo-tinta-2: var(--tinta-2); --cromo-tenue: var(--tenue);
  --cromo-acento: var(--acento);
}
body[data-arranjo="barra"] :is(#pilha-leitura, #barra-nav, #abas-alternar) {
  -webkit-backdrop-filter: saturate(1.4) blur(18px); backdrop-filter: saturate(1.4) blur(18px);
}
/* O véu de branco do destino ativo era para o grafite; sobre papel ele some,
   e o leito volta a ser o tingido de acento. */
body[data-arranjo="barra"] #barra-nav a[aria-current="page"] {
  background: color-mix(in srgb, var(--acento) 10%, transparent);
}
/* A barra de abas do telefone mede EXATAMENTE `--barra-h`. Media 62,6 px
   (itens de 52 + a folga da lista + o fio) contra os 58 do token, e a
   fileira, que pousa em `--barra-h`, cobria 4,6 px do topo dela — o fio entre
   as duas sumia ali (medido no simulador, 19/09). Os itens descem ao alvo de
   toque, que é o piso, e a altura passa a ser a do token que todos leem. */
body[data-arranjo="barra"] #barra-nav { box-sizing: border-box; height: var(--barra-h); }
body[data-arranjo="barra"] #barra-nav a { min-height: var(--alvo); padding-block: .3rem; }
/* Os ícones num tamanho só: o `▶` e o `⇕` são texto, o microfone, o `⇧` e
   o `✎` são desenho — e cada um herdava um tamanho de fonte de outra época
   (o microfone ainda a serifa de 1,35rem do antigo `?`). */
body[data-arranjo="barra"] :is(.capsula > button, #abas-alternar) svg { width: 22px; height: 22px; }
body[data-arranjo="barra"] #perguntar-flutuante { font-family: var(--sans); font-size: 1rem; }
body[data-arranjo="barra"] #ouvir-flutuante { font-size: 1.05rem; }

/* Lendo, sem o «≡»: uma barra só, no chão. `--pilha-y` desce junto, e os
   painéis que se ancoram nele (a folha da voz, as caixas, a tarja da versão)
   pousam acima da fileira, não acima de uma barra que não está lá. */
body[data-arranjo="barra"][data-leitura]:not([data-abas]) {
  --pilha-y: calc(var(--fileira-h) + env(safe-area-inset-bottom, 0px));
}
body[data-arranjo="barra"][data-leitura]:not([data-abas]) #barra-nav {
  transform: translateY(100%);
}
body[data-arranjo="barra"][data-leitura]:not([data-abas]) #pilha-leitura {
  bottom: 0; padding-bottom: env(safe-area-inset-bottom, 0px);
}
body[data-arranjo="barra"][data-leitura]:not([data-abas]) #tempo-leitura {
  bottom: env(safe-area-inset-bottom, 0px);
}
/* Com o «≡»: as abas voltam mesmo com o cromo oculto. Três atributos contra
   os dois de `body[data-leitura][data-cromo="oculto"] #barra-nav` — vence pela
   especificidade, não pela posição no arquivo. */
body[data-arranjo="barra"][data-leitura][data-abas] #barra-nav { transform: none; }
body[data-arranjo="barra"][data-leitura][data-abas] #tempo-leitura { bottom: var(--barra-h); }

/* O «≡» na ponta direita da fileira, fora dela (ver o `index.html`). Tem
   fundo próprio porque a fileira rola por baixo dele na tela do estudo. */
#abas-alternar { display: none; }
body[data-arranjo="barra"][data-leitura] #abas-alternar {
  display: grid; place-items: center;
  position: fixed; z-index: 47; right: 0; bottom: var(--barra-h);
  width: calc(var(--alvo) + .75rem + env(safe-area-inset-right, 0px)); height: var(--alvo);
  padding: 0 calc(.35rem + env(safe-area-inset-right, 0px)) 0 .4rem;
  background: var(--cromo-1); border: 0; border-left: 1px solid var(--cromo-borda); border-radius: 0;
  color: var(--cromo-tinta-2); cursor: pointer;
  transition: bottom var(--dur) var(--curva);
}
body[data-arranjo="barra"][data-leitura]:not([data-abas]) #abas-alternar {
  bottom: env(safe-area-inset-bottom, 0px);
}
body[data-arranjo="barra"] #abas-alternar[aria-expanded="true"] { color: var(--cromo-acento); }
body[data-arranjo="barra"] #abas-alternar:focus-visible { outline: 2px solid var(--foco); outline-offset: -2px; }

/* ── A folha da voz  (spec 63) ─────────────────────────────────────────────
   No telefone o bloco de quatro controles no alto do artigo (Ouvir, motor,
   Quem lê, Gerar) empurrava o texto 600 px para baixo e parecia formulário.
   Com a cápsula da voz em cena (`data-voz`), ele sai: o `▶` da fileira toca,
   e o `1,0×` abre esta folha, que já montava o motor, o «Quem lê» e a
   velocidade e agora leva o «Gerar» também. Sem `data-voz` (navegador sem
   fala e sem narração) o bloco fica, porque é o único caminho até a voz. */
body[data-arranjo="barra"][data-voz] .artigo > header :is(.controles-voz, .btn.ouvir) { display: none; }
body[data-arranjo="barra"] #velocidade-painel {
  left: .6rem; right: .6rem; width: auto;
  padding: 1rem 1rem 1.1rem;
  transform: translateY(.5rem);
}
body[data-arranjo="barra"] #velocidade-painel[data-aberto="sim"] { transform: none; }
body[data-arranjo="barra"] #velocidade-painel .controles-voz { gap: 1.1rem; }
body[data-arranjo="barra"] #velocidade-painel .fila-voz { gap: 1rem; }
body[data-arranjo="barra"] #velocidade-painel :is(.motor-voz, .timbre, .timbre select, .gerar-estudio) {
  width: 100%; max-width: none;
}
body[data-arranjo="barra"] #velocidade-painel .motor-voz .segmentado { display: flex; }
body[data-arranjo="barra"] #velocidade-painel .motor-voz .opcao { flex: 1; }
/* O `⇕` desce para a folha no telefone: com o «≡» na ponta, a fileira de
   440 px deixava o `✎` debaixo dele. Ele só age com a voz tocando, e já era
   da família da voz. O interruptor é a mesma pergunta, dita por extenso. */
.rolagem-folha { display: none; }
body[data-arranjo="barra"] #rolagem-flutuante { display: none; }
body[data-arranjo="barra"] #velocidade-painel .rolagem-folha {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  width: 100%; min-height: var(--alvo); padding: 0 .1rem;
  background: none; border: 0; border-top: 1px solid var(--regra);
  font: 500 .88rem/1.2 var(--sans); color: var(--tinta); cursor: pointer; text-align: left;
}
body[data-arranjo="barra"] #velocidade-painel .rolagem-folha::after {
  content: ""; flex: none; width: 38px; height: 22px; border-radius: 11px;
  background: radial-gradient(circle 8px at 11px 50%, var(--papel-elev) 97%, transparent) no-repeat,
              var(--borda-controle);
  transition: background-position var(--dur) var(--curva);
}
body[data-arranjo="barra"] #velocidade-painel .rolagem-folha[aria-pressed="true"]::after {
  background: radial-gradient(circle 8px at 27px 50%, var(--sobre-acento) 97%, transparent) no-repeat,
              var(--acento);
}
body[data-arranjo="barra"] #velocidade-painel .rolagem-folha:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* ── O topo desce abaixo da barra de status  (16/09) ──────────────────────
   O casco nativo pinta sob a barra de status (`ignoresSafeArea` + inset
   `.never`), e no iPhone os 1.7rem ficavam atrás do relógio e da ilha:
   «aquela barra superior está ficando muito em cima» (Yuri). O `max` deixa
   o Mac e o navegador como estavam (inset zero) e só desce onde há barra. */
.cabeca {
  max-width: var(--measure); margin: 0 auto;
  padding: max(1.7rem, calc(env(safe-area-inset-top, 0px) + .5rem)) max(1.1rem, env(safe-area-inset-left)) 0;
  display: flex; align-items: center; gap: .7rem;
  font-family: var(--sans); font-size: .84rem; line-height: 1;
}
/* Glifo e nome são **um link só**, e não dois vizinhos para o mesmo destino:
   dois links com o mesmo `href` lado a lado são duas paradas de teclado e duas
   leituras iguais no VoiceOver para uma única coisa. */
/* Sem min-height explícito de propósito: é `<a href="/">` de verdade — vai
   para a raiz —, alvo de toque real, não rótulo decorativo. Os ~30px do
   glifo dentro são só o ÍCONE; a caixa do link em si já herda os 44px do
   `--alvo` do núcleo (`:where(...,a[href])`) porque nada aqui redeclara
   `min-height` para vencer essa herança, e `.cabeca` (o pai) não tem altura
   fixa que corte a caixa. */
.cabeca .marca {
  display: inline-flex; align-items: center; gap: .7rem;
  font-weight: 600; font-size: 1rem; letter-spacing: -.01em;
  color: var(--tinta); text-decoration: none;
}
/* O glifo é a única superfície do app que veste o acento cheio. Ele existe
   para dar à `.cabeca` um ponto de ancoragem visual agora que ela não tem mais
   fundo nem filete — sem ele, o nome do app flutuaria solto no papel.
   Monocromático de propósito: a faixa amarela do ícone de verdade precisaria
   de texto escuro por cima para ser legível, e aqui a cor de cima é
   `--sobre-acento`. Um glifo de 18px não é lugar de resolver isso. */
.cabeca .glifo {
  width: 30px; height: 30px; border-radius: 9px; flex: none;
  background: var(--acento); color: var(--sobre-acento);
  display: grid; place-items: center;
}
.cabeca .glifo svg { width: 17px; height: 17px; display: block; }
.cabeca .fim { margin-left: auto; display: flex; align-items: center; gap: .5rem; }
.cabeca #aa {
  font-family: var(--sans); font-size: .8rem; font-weight: 600;
  color: var(--tinta-2); background: var(--papel-elev); border: 1px solid var(--regra);
  border-radius: 999px; min-width: 44px; min-height: 36px; padding: 0 .8rem; cursor: pointer;
}
.cabeca #aa:hover, .cabeca #aa:focus-visible { color: var(--acento); border-color: var(--acento); }
/* `inline-flex` + `align-items` (revisão 2026-08-24): o link herda os 44px
   de `--alvo` do núcleo, e sem o flex o texto assentava no TOPO dessa caixa
   — o «Sair» flutuava acima da linha do `Aa` ao lado. */
.cabeca #sair { color: var(--tenue); text-decoration: none; padding: .5rem .2rem;
  display: inline-flex; align-items: center; }
.cabeca #sair:hover, .cabeca #sair:focus-visible { color: var(--acento); }

/* ── A barra de baixo é o MESMO cromo da lateral  (02/09) ──────────────────
   Ela era vidro sobre a mesa: `--tela` a 82% com `backdrop-filter`. Isso fazia
   sentido enquanto o cromo do app inteiro era claro — e deixou de fazer no dia
   em que o Mac ganhou a lateral grafite. «No iPad aquela barra lá embaixo
   deveria ter sido na mesma cor grafite da barra lateral que aparece no
   MacBook» (Yuri, 02/09).

   É a mesma peça em duas diagramações — o mesmo `<nav>`, o mesmo DOM, a mesma
   ordem de leitura —, e uma peça que muda de MATERIAL conforme a largura da
   tela é duas peças. O vidro sai junto: sobre um campo escuro e opaco ele não
   tem o que borrar, e o `backdrop-filter` custa composição a cada quadro de
   rolagem no aparelho mais fraco dos dois.

   O gradiente é vertical numa faixa de 58px, então quase chapado — e é de
   propósito: são os mesmos dois tokens da lateral, e o dia em que a lateral
   mudar de tinta, esta muda junto. */
#barra-nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  padding-bottom: env(safe-area-inset-bottom);
  background: linear-gradient(180deg, var(--cromo-1), var(--cromo-2));
  border-top: 1px solid var(--cromo-borda);
  transition: transform var(--dur) var(--curva);
}
#barra-nav[hidden] { display: none; }
#barra-nav ul {
  list-style: none; margin: 0 auto; max-width: var(--measure); display: flex; gap: .2rem;
  padding: .3rem max(.6rem, env(safe-area-inset-left));
}
#barra-nav li { flex: 1; }
#barra-nav a {
  display: flex; flex-direction: column; align-items: center; gap: .18rem;
  text-decoration: none; color: var(--cromo-tinta-2);
  font-family: var(--sans); font-size: .66rem; font-weight: 500; letter-spacing: .01em;
  padding: .45rem .2rem; min-height: 52px; border-radius: var(--raio-p);
}
/* Ícone **e** rótulo. Ícone sozinho num app de um leitor só é adivinhação com
   estética: não há onboarding, não há tooltip no iPad, e o custo do rótulo são
   dez pixels de altura que a barra já tem de sobra para o alvo de 52px. */
/* SVG, não glifo de texto (revisão 2026-08-24): "▤" e "✦" eram fonte, e
   fonte muda de peso por família — os dois ícones da barra nunca tinham o
   mesmo traço. Os desenhos vivem em `ICONES` no app.mjs, na gramática do
   GLIFO; aqui só a caixa. */
#barra-nav a .ic { display: block; height: 21px; }
#barra-nav a .ic svg { width: 21px; height: 21px; display: block; }
#barra-nav a:hover, #barra-nav a:focus-visible { color: var(--cromo-acento); }

/* A contagem é da LATERAL, e não da barra — e desde 04/09 só das PRATELEIRAS,
   dentro da estante: os destinos (Inbox, Destaques, Estante, Escrivaninha)
   perderam o número, que contava uma partição diferente da que a tela lista
   («Inbox 31» com cinco na aba). A prateleira conta o que ela mesma mostra.

   Na barra inferior nenhuma contagem aparece: o item é uma coluna — ícone em
   cima, palavra embaixo —, então o número viraria uma TERCEIRA linha empilhada
   num alvo de 52px. A barra é para ir a algum lugar, não para saber quanto tem
   lá. */
#barra-nav a .conta { display: none; }

/* ── No Mac os três destinos saem da barra e vão para a LATERAL  (1e) ───────
   «Barra inferior é idioma de dedo, não de trackpad.» É a adaptação por
   plataforma mais concreta desta rodada, e ela é de CSS: o mesmo `<nav>`, o
   mesmo DOM, a mesma ordem de leitura — só a diagramação muda.

   O corte é 1100px e não 900px de propósito. O iPad em paisagem tem 1180pt e
   continua sendo um aparelho de dedo: pôr a lateral nele tiraria a navegação
   do alcance do polegar para ganhar nada. 1100px com `pointer: fine` pede as
   DUAS coisas — tela grande E apontador de precisão —, que juntas só
   descrevem um computador de mesa.

   `--barra-h` vai a zero aqui porque ele é a folga reservada EMBAIXO: com a
   barra na lateral, aquela faixa morta viraria um rodapé em branco. */
/* ── Este bloco vem ANTES da @media da lateral, e isso é de propósito ─────
   Ele e a regra do ativo lá dentro têm a MESMA especificidade (um id, um
   tipo, um atributo), e `@media` não empresta peso nenhum — quem vence é a
   última no arquivo. Enquanto este bloco ficou depois, o ativo da lateral
   grafite saía pintado com o acento do PAPEL e com o leito de 9% por cima do
   cromo. É o mesmo modo de falha que o comentário do `translateY(100%)`
   registra no fim da media query, e o remédio é o mesmo: ordem. */
/* O ativo, nos DOIS modos. `--cromo-acento` porque o campo é grafite em ambos
   — a brasa funda do tema claro mede 1,55:1 sobre ele e desaparece. O leito de
   branco a 7% substitui o tingido de acento a 9%: sobre escuro, quem levanta
   uma superfície é luz, não cor. */
#barra-nav a[aria-current="page"] {
  color: var(--cromo-tinta); font-weight: 600;
  /* 8%, não 9 (revisão 2026-08-24): com o sépia rosa-velho o tingido de
     acento deixou de sair salmão-por-acidente, e um ponto a menos devolve à
     pílula o peso de estado — presença que se nota ao procurar, não mancha
     que se nota antes do rótulo.

     2026-09-01 — volta a 9% (prancha 1d). A razão do desconto era o carmim
     virando salmão POR ACIDENTE sobre o papel rosado do sépia; a brasa é
     laranja-avermelhada de propósito, então o tingido quente deixou de ser
     acidente e passou a ser o desenho. O ponto devolvido é o que sustenta o
     que a prancha cobra: cor sozinha, no vidro, some contra papel claro
     visto em ângulo — o leito é o que salva o estado nessa condição.

     2026-09-02 — o tingido de acento sai e entra o véu de branco: o campo
     deixou de ser papel e virou grafite nos dois modos. */
  background: rgba(255,255,255,.07);
}
#barra-nav a[aria-current="page"] .ic { color: var(--cromo-acento); }

/* ── Este bloco vem ANTES da @media da lateral, e isso é de propósito ─────
   Terceira vez que a mesma armadilha aparece nesta rodada: a regra genérica e
   a da lateral têm a mesma especificidade (uma classe), `@media` não empresta
   peso, e quem vence é a última no arquivo. Enquanto este bloco ficou depois,
   o `.nav-rodape` da lateral nascia `display: none` — o `Aa`, o `Sair` e o
   carimbo simplesmente não apareciam no Mac, e o teste de CSS não pega isso
   porque as duas regras existem e as duas estão certas.

   A marca escapava por acidente: `#barra-nav a` (um id) tem especificidade
   maior que `.nav-marca` e a mantinha visível. Acidente que salva um dos três
   é pior que defeito que derruba os três. */
/* A marca, as prateleiras e o rodapé são da LATERAL. Na barra inferior eles
   caíam como texto solto e enorme embaixo dos três destinos — o `<p>` herdava
   a serifa do corpo porque a regra que os desenha vive na media query da
   lateral, e fora dela não havia regra nenhuma. Um elemento sem estilo não é
   um elemento discreto: é o estilo do documento aparecendo.

   O `.nav-rodape` entrou na lista em 02/09 e some com os irmãos — mas o que
   ele carrega NÃO some com ele: `Aa` e `Sair` já saíram daqui para a
   `.cabeca` antes da pintura (`acomodarControles`, em `app.mjs`), e o carimbo
   de versão continua no `#versao` do fluxo, que só se recolhe no modo
   lateral. Nenhum dos três aparece duas vezes na mesma tela, e nenhum
   desaparece das duas. */
/* `#barra-nav .nav-marca`, e não `.nav-marca` sozinha: desde 02/09 a marca é
   um `<a>`, e `#barra-nav a { display: flex }` (um id) vencia a classe — no
   iPad ela aparecia DENTRO da barra inferior, como um quarto destino gigante.
   Enquanto era um `<p>`, a regra curta bastava; o elemento mudou e a
   especificidade mudou com ele. */
#barra-nav .nav-marca, #nav-prateleiras, .nav-rodape { display: none; }

@media (min-width: 1100px) and (pointer: fine) {
  :root { --barra-h: 0px; }

  /* ── A lateral é CROMO, e cromo é grafite nos três temas  (02/09) ────────
     O que havia aqui: `--papel-elev-2` — um dos três beges que vivem dentro
     de 1,2:1 de razão uns dos outros (`--tela`, `--papel-elev-2`,
     `--papel-elev`). A coluna de navegação pintada com um deles é uma coluna
     que não se separa da mesa, e era essa a queixa que abriu a rodada: «são
     muitos tons pastéis sobrepostos».

     A saída é um corte de valor só — cromo escuro contra papel claro —, e ele
     responde «onde eu ando» × «o que eu leio» sem gastar cor nenhuma. Os
     tokens `--cromo-*` moram no núcleo do Scriptorium: é verdade de qualquer
     app, e a nota lá explica por que eles não mudam por tema.

     Os dois ajustes por tema abaixo são cosméticos, com uma exceção que não
     é: no ESCURO a mesa é `#14171a`, e o cromo tem de ficar um degrau mais
     CLARO que ela — no escuro a lateral não pode ser a parte mais funda da
     tela, senão ela deixa de ser objeto e vira buraco. */
  #barra-nav {
    top: 0; bottom: 0; right: auto; width: 236px;
    border-top: 0; border-right: 1px solid var(--cromo-borda);
    padding: 22px 0 16px; padding-left: env(safe-area-inset-left);
    overflow-y: auto;
    background: linear-gradient(180deg, var(--cromo-1), var(--cromo-2));
    backdrop-filter: none; -webkit-backdrop-filter: none;
    display: flex; flex-direction: column;
  }

  /* ── A marca volta a ser A MARCA  (era um rótulo de 10px) ────────────────
     No papel claro ela vivia na `.cabeca`, dentro da coluna de leitura, e a
     lateral só tinha o nome do app em versalete miúdo. Sobre grafite é ela
     que ancora a coluna: glifo de 30px e o nome em 16px, os mesmos da
     `.cabeca` — que some inteira neste modo, logo adiante.

     `--cromo-acento` é o acento do tema ESCURO em qualquer tema, e o glifo por
     cima dele é `--cromo-2`, a base do próprio gradiente. Sobre grafite a
     brasa funda do tema claro desapareceria. */
  #barra-nav .nav-marca {
    display: flex; align-items: center; gap: .7rem; flex: none;
    margin: 0; padding: 0 18px 18px;
    font: 600 16px/1 var(--sans); letter-spacing: -.01em;
    color: var(--cromo-tinta); text-decoration: none; text-transform: none;
  }
  .nav-marca .glifo {
    width: 30px; height: 30px; border-radius: 9px; flex: none;
    background: var(--cromo-acento); color: var(--cromo-2);
    display: grid; place-items: center;
  }
  .nav-marca .glifo svg { width: 17px; height: 17px; display: block; }

  #barra-nav ul {
    flex-direction: column; gap: 2px; max-width: none;
    padding: 0 12px;
  }
  #barra-nav li { flex: 0 0 auto; }
  /* Deitado: ícone à esquerda do rótulo, como qualquer lateral. O alvo de
     44px fica — ele é de acessibilidade, não de dedo. */
  #barra-nav a {
    position: relative;
    flex-direction: row; justify-content: flex-start; gap: 11px;
    font: 500 13.5px/1 var(--sans); letter-spacing: 0;
    padding: 11px 12px; min-height: 44px; border-radius: 8px;
    color: var(--cromo-tinta-2);
  }
  #barra-nav a .ic, #barra-nav a .ic svg { width: 20px; height: 20px; }
  #barra-nav a:hover, #barra-nav a:focus-visible {
    /* Véu de branco puro, e não uma cor: sobre cromo o realce é LUZ, e uma
       cor aqui teria de existir em três temas para dizer a mesma coisa. */
    background: rgba(255,255,255,.045); color: var(--cromo-tinta);
  }
  /* O ativo é fundo + peso + ícone no acento + filete colado à esquerda. São
     quatro pistas porque o leito sozinho, sobre grafite, é sutil demais — e
     porque nenhuma delas é cor apenas. */
  /* O leito, o peso e o ícone acentuado do ativo vêm do bloco global (o cromo
     é o mesmo nos dois modos). O que a lateral acrescenta é o FILETE: numa
     coluna vertical ele marca a linha inteira, e na barra horizontal de 58px
     não haveria onde pousá-lo. */
  #barra-nav a[aria-current="page"]::before {
    content: ""; position: absolute; left: 0; top: 9px; bottom: 9px;
    width: 2px; border-radius: 2px; background: var(--cromo-acento);
  }
  /* A contagem das prateleiras é informação (mesma tese do `--tenue`), então
     responde ao piso de 4.5:1 como qualquer texto — `--cromo-tenue` está
     medido contra os dois extremos do gradiente. No ativo ela sobe junto com a
     linha. */
  #barra-nav a .conta {
    display: block;
    margin-left: auto; font: 500 11.5px/1 var(--sans); color: var(--cromo-tenue);
    font-variant-numeric: tabular-nums;
  }
  #barra-nav a[aria-current="page"] .conta {
    color: color-mix(in srgb, var(--cromo-tinta) 78%, transparent); opacity: 1;
  }

  .nav-titulo {
    font: 600 10px/1 var(--sans); letter-spacing: .12em; text-transform: uppercase;
    color: var(--cromo-tenue); margin: 0; padding: 18px 18px 8px;
  }
  /* As prateleiras não têm ícone: são recortes do mesmo acervo, não destinos.
     O recuo é o que diz isso sem precisar de palavra. */
  #nav-prateleiras ul { padding: 0 12px; }
  #nav-prateleiras a {
    padding: 9px 12px 9px 33px; font: 500 12.5px/1 var(--sans);
    min-height: 38px; border-radius: 7px; color: var(--cromo-tinta-2);
  }
  #nav-prateleiras[hidden] { display: none; }

  /* ── O rodapé da lateral: `Aa`, `Sair` e o carimbo  (02/09) ──────────────
     Os dois controles que NÃO são navegação moravam na `.cabeca`, dentro da
     coluna de leitura. Aqui eles descem para o pé do cromo, que é onde se
     procura o que configura o app — e a `.cabeca` some, porque tudo o que ela
     carregava passou a ter casa melhor.

     `margin-top: auto` cola o bloco no fim da coluna; é o que faz o rodapé ser
     rodapé mesmo com três destinos e nenhuma prateleira. */
  .nav-rodape {
    margin-top: auto; flex: none;
    display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
    padding: 14px 18px 0; margin-left: 0; margin-right: 0;
    border-top: 1px solid var(--cromo-borda);
  }
  .nav-rodape #aa {
    font: 600 12px/1 var(--sans); color: var(--cromo-tinta);
    background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.1);
    border-radius: 999px; min-width: 0; min-height: 32px; padding: 0 13px;
    cursor: pointer;
  }
  .nav-rodape #aa:hover, .nav-rodape #aa:focus-visible {
    color: var(--cromo-acento); border-color: var(--cromo-acento);
  }
  .nav-rodape #sair {
    font: 500 12px/1 var(--sans); color: var(--cromo-tenue);
    text-decoration: none; padding: 0; min-height: 32px;
    display: inline-flex; align-items: center;
  }
  .nav-rodape #sair:hover, .nav-rodape #sair:focus-visible { color: var(--cromo-acento); }
  /* O carimbo responde «a versão que estou vendo é a que subiu?», e ele é
     lido com ATENÇÃO quando alguém pergunta — por isso ele não desce de cor
     para se recolher (o `#versao` do fluxo já recusou `opacity` pela mesma
     razão): quem o recolhe é o tamanho. */
  .nav-rodape .nav-versao {
    flex-basis: 100%; font: 500 10.5px/1.4 var(--sans); letter-spacing: .05em;
    color: var(--cromo-tenue); font-variant-numeric: tabular-nums;
  }

  /* ── A `.cabeca` e o `#versao` do fluxo somem  (02/09) ───────────────────
     Tudo o que os dois carregavam mora agora no cromo: a marca no topo da
     lateral, o `Aa` e o `Sair` no rodapé dela (movidos de pai por
     `acomodarControles`, não copiados), e o carimbo ao pé. Deixá-los na tela
     seria a marca duas vezes e o carimbo duas vezes.

     A folga que o `#versao` reservava embaixo não se perde: ela era
     `--barra-h`, e `--barra-h` é 0 aqui — não há barra sob a qual o fim da
     lista possa cair. */
  body[data-dentro] .cabeca,
  body[data-dentro] #versao { display: none; }

  /* O conteúdo abre espaço para a lateral. `margin`, e não `padding`, para o
     `max-width: var(--measure)` do `main` seguir medindo a COLUNA e não a
     coluna mais a barra — a medida da linha é o ativo mais protegido deste
     app, e some sem avisar se a conta mudar de base. */
  body[data-dentro] main { margin-left: 236px; }
  /* O cromo escondido leva esta lateral para o LADO, e não para baixo — mas a
     regra que faz isso **não mora aqui**: ela mora na seção do cromo, adiante,
     logo depois da regra do modo barra. A razão é de cascata, não de arrumação
     (2026-09-02): as duas têm a mesma especificidade, então quem vence é a
     última no arquivo — e enquanto esta ficou aqui em cima, o `translateY(100%)`
     de baixo venceu sempre. A lateral sumia deslizando para BAIXO, que é o
     gesto errado para uma barra vertical, e ninguém notou porque some de
     qualquer jeito. Estar dentro de uma `@media` não empresta peso nenhum. */
}

/* ── conteúdo ────────────────────────────────────────────────────────────── */
main {
  max-width: var(--measure);
  margin: 0 auto;
  /* A folga da barra fixa saiu daqui e foi para o `#versao` (L-71): quem
     precisa dela é o ÚLTIMO elemento do fluxo, e o último passou a ser o
     carimbo de versão, não o `main`. Mantida aqui, o carimbo cairia atrás da
     barra — e a folga apareceria duas vezes, uma em cada elemento. */
  padding: 1.6rem max(1.1rem, env(safe-area-inset-left)) 1.5rem;
}

/* ── o carimbo do build  (L-71) ───────────────────────────────────────────
   Responde a uma pergunta só, e a pergunta é operacional: «a versão que estou
   vendo é a que subiu?». Ela apareceu do jeito caro — botões novos que não
   apareciam no iPad, sem como distinguir "o deploy não pegou" de "o cache é
   velho" de "o código está errado". Sem carimbo, essas três hipóteses custam
   uma sessão de depuração cada.

   Alinhado à direita e em 10px: é para ser CONFERIDO quando alguém pergunta,
   não lido no caminho. E sem `opacity` — o que o recolhe é o tamanho, não a
   transparência, que tiraria contraste justamente de um texto cuja única
   função é ser lido com atenção. Mesma decisão registrada no `.versao` do
   Tabula. */
#versao {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 max(1.1rem, env(safe-area-inset-left)) calc(var(--barra-h) + 1.5rem);
  font-family: var(--sans); font-size: 10px; letter-spacing: .06em;
  font-variant-numeric: tabular-nums; color: var(--tenue); text-align: right;
}
/* Sem regra `:empty` de propósito, e a razão é a garantia acima dele: este
   elemento é o ÚLTIMO do fluxo, então é o padding DELE que impede o fim da
   lista de ficar debaixo do vidro da barra. Escondê-lo quando vazio faria a
   folga sumir junto — e sumiria justamente no caso em que o `app.mjs` não
   rodou, que é quando a tela já está estranha e ninguém suspeitaria do CSS.
   Vazio ele não mostra nada; só reserva o fim, que é o trabalho. */
/* Na rota de leitura, quem contém a coluna é a folha (`.artigo`), não o
   `main` — ela precisa ser mais larga que `--measure` para sobrar respiro
   dos dois lados (§1). Sem isto o `main` travaria a folha em `--measure`
   antes de o respiro entrar em cena, e a folha nasceria do mesmo tamanho do
   texto que carrega — apertada, não pousada. `data-rota` já existe no
   `<body>` para exatamente este tipo de regra (ver `app.mjs:160`). */
/* ── `data-leitura`, e não mais `data-rota="artigo"`  (spec 23 §6.3) ────────
   Estas regras nunca perguntaram «que rota é esta?»; perguntavam «esta tela é
   de leitura?» — e enquanto houve uma só tela de leitura, as duas perguntas
   tinham a mesma resposta. A escrivaninha põe uma segunda: a rota `/e/:id` É o
   leitor de artigo, montado sobre o documento da etapa, e ela precisa da
   tipografia, do sumário, da narração e do cromo que some ao rolar.
   Duplicar quinze seletores em `[data-rota="estudo"]` seria manter duas listas
   que precisam concordar para sempre. O atributo passa a nomear o que a regra
   de fato quer saber, e quem o escreve é `aoNavegar`, a partir da própria
   tabela de rotas — uma tela de leitura nova o ganha declarando `leitura:
   true`, e não editando CSS. */
body[data-leitura] main { max-width: none; padding: 0; }
main h1 { font-size: 1.5em; line-height: 1.25; margin: 0 0 .3em; }
main p { margin: 0 0 var(--space-para); }
.sub { color: var(--tinta-2); font-family: var(--sans); font-size: .82rem; }
.vazio { color: var(--tinta-2); font-style: italic; padding: 3rem 0; text-align: center; }

/* ── tela de entrada (L-69) ────────────────────────────────────────────────
   A única tela em que o app se apresenta, e a primeira que um aparelho novo
   vê. É aqui que a direção investe: ícone grande, botão com alvo de 52px e um
   lençol de cor ao fundo. Nada disto contraria a 02 §1 — ela fala da tela de
   leitura (D3), e esta é o oposto dela. */
#login {
  min-height: 62vh; display: flex; flex-direction: column; justify-content: center;
  align-items: center; text-align: center; position: relative;
}
/* O lençol: um halo do acento atrás do ícone. `pointer-events: none` porque ele
   cobre o botão — um brilho que engole o toque é o defeito mais bobo possível
   na única tela que precisa de um toque só. */
#login::before {
  content: ""; position: absolute; inset: -10% -30% auto -30%; height: 70%;
  pointer-events: none;
  /* 15% (prancha 1b), e não os 13% de antes: com a brasa o lençol esquenta o
     papel em vez de esfriá-lo, e dois pontos a mais é o que o desenho pede
     para ele continuar sendo lençol e não névoa. O ÍCONE não mudou — o
     mockup da prancha traz um glifo de livro genérico, marcador de posição;
     o real é a folha com o trecho marcado, que tem razão escrita no próprio
     SVG e teste que a guarda ("o ícone é a COLUNA DE TEXTO"). */
  background: radial-gradient(60% 60% at 50% 30%,
    color-mix(in srgb, var(--acento) 15%, transparent), transparent 70%);
}
#login .icone {
  width: 76px; height: 76px; border-radius: 20px; margin: 0 0 1.6rem; display: block;
  box-shadow: 0 10px 30px color-mix(in srgb, var(--acento) 22%, transparent);
}
#login h1 {
  font-family: var(--serif); font-size: 1.85em; font-weight: 600; line-height: 1.2;
  letter-spacing: -.02em; margin: 0 0 .5rem;
}
#login .sub { font-size: .94rem; max-width: 23em; line-height: 1.55; margin: 0 0 2.2rem; }
/* Botão, e não link de texto: 52px de alvo, fundo de acento e a cor de cima
   vinda de `--sobre-acento` — nunca `#fff`, que no tema escuro dava ~2:1. */
#login .entrar {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--sans); font-size: .95rem; font-weight: 600;
  color: var(--sobre-acento); background: var(--acento);
  border: 0; border-radius: var(--raio); text-decoration: none;
  padding: 0 2.4rem; min-height: 52px; min-width: 14rem; cursor: pointer;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--acento) 25%, transparent);
}
#login .entrar:hover, #login .entrar:focus-visible { filter: brightness(1.08); }
#login .rodape {
  font-family: var(--sans); font-size: .75rem; color: var(--tenue); margin: 1.6rem 0 0;
}

/* ── inbox e clusters (L-47, L-67) ─────────────────────────────────────────
   **O título do item é serifado; o resto da lista não** (02 §2.1, D4). A regra
   antiga — "navegar é varrer, ler é demorar" — punha a lista inteira em sans, e
   continua valendo para resumo, crédito e rótulo, que são navegação. O título
   volta à Literata porque ele não é rótulo: é o começo da leitura, e é por ele
   que se decide abrir.

   Os tokens de tamanho da coluna (`--measure`) valem aqui também — a lista não
   fica larga num monitor grande, porque varrer uma linha de 140 caracteres é
   pior que rolar.
   ───────────────────────────────────────────────────────────────────────── */

/* ── Controle segmentado: um alvo, três opções, estado sempre visível ──────
   As três abas com filete embaixo da palavra dependiam de 2px para dizer onde
   se está — e de relance, no iPad, custavam um segundo olhar. */
.abas.seg {
  display: flex; gap: .15rem; margin: 0 0 1rem;
  background: var(--papel-elev-2); border-radius: var(--raio-p); padding: .22rem;
  font-family: var(--sans);
}
.abas.seg .aba {
  flex: 1; text-align: center; text-decoration: none; color: var(--tinta-2);
  font-size: .82rem; font-weight: 500; padding: .5rem .4rem; min-height: 38px;
  border-radius: 6px; display: flex; align-items: center; justify-content: center;
}
.abas.seg .aba:hover, .abas.seg .aba:focus-visible { color: var(--acento); }
/* O ativo é uma superfície que sobe do trilho, não uma cor de texto: é o que o
   dedo procura, e sobrevive a qualquer tema. */
.abas.seg .aba.ativa {
  background: var(--papel-elev); color: var(--tinta); font-weight: 600;
  /* pousada: sobe do trilho, não do papel — a mais rasa das superfícies que
     usavam --sombra crua. Os degraus do núcleo já são o box-shadow inteiro
     (duas camadas), não uma cor a compor — por isso o token substitui a
     declaração toda, não só a cor. */
  box-shadow: var(--sombra-pousada);
}

.clusters { font-family: var(--sans); font-size: .82rem; margin: 0 0 1.4rem; }
.clusters .fileira {
  display: flex; gap: .4rem; overflow-x: auto; scrollbar-width: none; padding-bottom: .2rem;
}
.clusters .fileira::-webkit-scrollbar { display: none; }

/* Borda em --borda-controle, não --regra (§2): o fundo próprio (--papel-elev
   sobre --tela) mede só 1,09–1,29:1 — tom demais para contar como pista, de
   longe abaixo do piso de 3:1 — então a borda é a única coisa que diz "isto
   é um chip", e precisa do piso que --regra não garante. */
.chip { display: inline-flex; align-items: center; gap: .4rem; flex: none;
  text-decoration: none; font-size: .79rem; font-weight: 500;
  color: var(--tinta-2); background: var(--papel-elev); border: 1px solid var(--borda-controle);
  border-radius: 999px; padding: .42rem .8rem; min-height: 34px; white-space: nowrap; }
.chip:hover, .chip:focus-visible { color: var(--acento); border-color: var(--acento); }
/* O chip ativo veste a matiz do PRÓPRIO tema, e não o acento: é o que impede a
   fileira de dizer "cyber" com a cor do app. Sem `--t` — cluster fora da
   tabela e sem hash — cai no acento, que é o comportamento de antes. */
.chip.ativo {
  color: var(--tinta); border-color: var(--t, var(--acento));
  background: color-mix(in srgb, var(--t, var(--acento)) 10%, var(--papel-elev));
}
.chip .ponto { width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--t, var(--tenue)); }
.chip .conta { color: var(--tenue); font-variant-numeric: tabular-nums; font-size: .74rem; }

.lista { list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: .6rem; }
/* O cartão (D3). O filete de 1px que separava os itens virou a borda de uma
   superfície própria: a diferença é que agora o alvo do dedo tem contorno, e no
   iPad um alvo com contorno é um alvo que se acerta.

   Borda em --borda-controle, não --regra (Onda 3, correção): o `.item` mora
   sobre `--tela` (a mesa, ver `body` acima), e `--regra` × `--tela` mede
   1,003:1 no claro e 1,001:1 no sépia — o contorno que este comentário
   promete tinha sumido de novo, coincidência de cor entre os dois tokens, não
   escolha. `--borda-controle` é o token que o núcleo já garante com piso 3:1
   contra as três superfícies (3,359 claro / 3,631 sépia / 4,570 escuro contra
   --tela) — o mesmo caso que `.chip` já resolve dois parágrafos abaixo, e o
   card inteiro É o alvo do dedo, exatamente o que `--borda-controle` existe
   para marcar. */
/* ── A LOMBADA virou a pista, e a borda saiu do caminho  (02/09) ───────────
   O comentário acima conta que a borda subiu de `--regra` para
   `--borda-controle` porque o contorno sumia contra a mesa. O contorno voltou
   a aparecer e a lista ficou com um retângulo cinza em volta de cada cartão —
   catorze deles numa tela, todos do mesmo peso. Era a metade cara da queixa
   «os cards são sem graça»: peso igual em tudo é ausência de hierarquia.

   O que entra no lugar são DUAS pistas, e nenhuma delas é a borda:

     · a **lombada** de 3px na matiz do tema, colada à esquerda. Ela é a mesma
       cor que a sobrancelha já usa, então não é vocabulário novo — é a cor do
       cluster ganhando corpo. E é a razão pela qual baixar a borda é legítimo:
       o piso de 3:1 vale para borda que é a ÚNICA pista de controle, e aqui
       ela deixou de ser;
     · a **sombra**, que é o que o núcleo já manda usar para separar folha de
       mesa (a nota de `--papel-borda`: «é a sombra que separa a folha da mesa,
       não o contraste de cor»). O cartão pousa em `--sombra-pousada` e sobe
       para `--sombra-erguida` no hover — o mesmo par das `.abas.seg`.

   A lombada é OBRIGATÓRIA. Cluster fora da tabela e sem hash cai no acento,
   como o `.chip` já faz, e `inbox.test.mjs` cobra que todo `.item` tenha cor
   resolvida: sem ela o cartão fica sem pista nenhuma, que é pior do que
   estava antes.

   `overflow: hidden` para o raio de 12px cortar a faixa nos dois cantos da
   esquerda; sem ele a lombada é um retângulo que escapa pela quina. */
.item {
  background: var(--papel-elev); border: 1px solid var(--papel-borda-fina);
  border-radius: var(--raio); box-shadow: var(--sombra-pousada);
  padding: 17px 20px 15px 23px; position: relative; overflow: hidden;
}
.item:hover { box-shadow: var(--sombra-erguida); }
.item .lombada {
  position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--t, var(--acento));
}
.item .alvo { display: block; text-decoration: none; color: inherit; }
/* A sobrancelha: versalete na matiz do tema. Ela é o segundo lugar onde a cor
   do cluster aparece, e o primeiro em que ela vem com a palavra junto — é
   assim que o olho aprende a associar as duas. */
/* A sobrancelha e o CRÉDITO dividem a primeira linha (02/09). O crédito
   («fonte · minutos · data») é procedência, e procedência pertence ao alto do
   cartão, junto do tema — embaixo ele disputava a linha com a barra de
   progresso e cinco botões, e era o primeiro a ceder com reticências.
   `align-items: baseline` porque são duas tipografias de tamanhos diferentes
   na mesma linha: o que tem de alinhar é a base das letras, não as caixas. */
.item .eyebrow {
  display: flex; align-items: baseline; gap: 10px; margin: 0 0 7px;
  font-family: var(--sans);
}
.item .eyebrow .temas {
  font-size: 10px; font-weight: 600; letter-spacing: .11em; text-transform: uppercase;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.item .eyebrow a { color: var(--t, var(--tenue)); text-decoration: none; }
.item .eyebrow a:hover, .item .eyebrow a:focus-visible { text-decoration: underline; }
/* `flex: none` e empurrado à direita: o crédito não encolhe mais, porque quem
   cede agora é a lista de temas ao lado — um tema pela metade ainda diz de que
   tema é, e "31 ju" não é uma data. */
.item .eyebrow .meta {
  margin-left: auto; flex: none;
  font-size: 11.5px; font-weight: 400; color: var(--tenue);
}
.item h2 { font-family: var(--serif); font-size: 21px; line-height: 1.28;
  margin: 0 0 7px; font-weight: 600; letter-spacing: -.008em; text-wrap: balance; }
.item .alvo:hover h2, .item .alvo:focus-visible h2 { color: var(--acento); }
.item .resumo { font-family: var(--sans); font-size: 13.5px; color: var(--tinta-2);
  margin: 0 0 13px; line-height: 1.55; text-wrap: pretty; }
.item .rodape { font-family: var(--sans); font-size: .74rem; color: var(--tenue); }
/* A palavra de estado, onde o crédito estava. Ver `estadoEmPalavra` no
   `inbox.mjs`: na aba «Todos» ela é a única pista visível de que um item já
   foi lido — os botões mostram a AÇÃO, não o estado. */
.item .rodape .estado {
  font-size: 11.5px; font-weight: 500; color: var(--tenue);
}
/* As ações encolhem para 29px e vão para a direita da linha. Exceção
   deliberada ao `--alvo` de 44px, no mesmo registro que `.linha-progresso
   .redondo` (32px) já abriu: são alvos SECUNDÁRIOS dentro de um cartão que
   tem área de toque própria e bem maior. O `min-height` explícito é o que
   impede o `min-height: 44px` do núcleo de vencer o `height` e transformar o
   círculo numa elipse — é o defeito que aquele comentário descreve. */
/* O grupo da direita começa no SINAL da voz de estúdio quando ele existe, e
   nas ações quando não: desde 14/09 o sinal só é desenhado com narração
   pronta ou gerando, e sem ele as ações têm de ir sozinhas para a direita. */
.item .rodape .sinal-estudio, .item .rodape .acoes { margin-left: auto; }
.item .rodape .sinal-estudio + .acoes { margin-left: 0; }
.item .rodape .sinal-estudio { flex: none; padding-inline: 4px; }
.item .rodape .acoes { display: flex; gap: 5px; }
/* Todos os redondos do rodapé, e não só os de dentro de `.acoes`: o `↺` de
   reler mora fora dela, e ficava sendo o único de 32px numa fileira de 29 —
   visível na primeira captura desta rodada, invisível para os testes. */
.item .rodape .redondo {
  width: 29px; height: 29px; min-height: 29px; font-size: 12.5px;
  border-color: var(--aro-fino);
}
.item .rodape .acoes .excluir:hover, .item .rodape .acoes .excluir:focus-visible {
  color: var(--perigo); border-color: var(--perigo);
}
/* `flex: none` até a L-70, e a mudança é consequência dela: a linha ganhou
   mais dois botões de 32px, e com o crédito rígido ela estourava a largura do
   cartão no iPhone — empurrando o ✕ para fora em vez de encurtar
   "exemplo.com · 9 min · 31 jul", que é o que ali sobra de dispensável.
   Agora o crédito é o PRIMEIRO a ceder, e cede com reticências: os botões e o
   percentual seguem `flex: none`, porque um botão pela metade não é um botão
   e "6" não é "62%". */
.item .rodape .meta {
  flex: 0 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Piso da barra: `flex: 1` também encolhe, e uma barra de progresso de 8px
   não informa nada — melhor encurtar mais o crédito. */
.linha-progresso .progresso { min-width: 3rem; }
.item .pct { font-variant-numeric: tabular-nums; flex: none; }

/* No telefone, o crédito ganha a linha inteira em vez de caber por reticências.
   Medido: num cartão de 360px a linha sobra 292px, e com barra + `62%` + ↺ +
   os três botões o crédito era espremido a 39px — o que a reticência entrega
   ali é a letra "e", que não é informação, é entulho. Acima disso (iPad, que é
   onde este app vive) nada muda: tudo continua numa linha só.

   `flex: 1 0 100%` e não `flex-basis: 100%` solto: o `0` de shrink é o que
   impede o crédito de ser puxado de volta para a primeira linha quando o
   título é curto. */
/* A regra que dava a linha inteira ao crédito no telefone saiu em 02/09 junto
   com o crédito: ele subiu para a linha da sobrancelha, onde tem a largura do
   cartão só para ele e não disputa com barra nem com botão. O que sobrou
   embaixo é a palavra de estado (ou a barra) mais os alvos, que cabem em
   360px sem quebrar. */

/* Barra de progresso: 4px, e agora COM número ao lado. Sozinha ela responde
   "quanto falta" de relance; o número responde "vale a pena terminar agora?",
   que é a pergunta de quem está escolhendo entre dois artigos. */
.progresso { height: 4px; background: var(--papel-elev-2); border-radius: 2px; overflow: hidden; }
.progresso span { display: block; height: 100%; background: var(--t, var(--acento));
  border-radius: 2px; }

.vazio.erro { font-style: normal; color: var(--tinta); }
.voltar { font-family: var(--sans); font-size: .82rem; margin: 0 0 .4rem; }
.voltar a { color: var(--tinta-2); text-decoration: none; }
.voltar a:hover { color: var(--acento); }

/* ── tela de leitura (L-48) ────────────────────────────────────────────────
   "A página desaparece" (02 §1). O leitor não deve notar a tipografia — deve
   notar que leu 4.000 palavras sem cansar. Tudo aqui serve a isso: nada
   pisca, nada salta, nada compete com o texto. O único elemento com direito a
   chamar atenção é o destaque, porque ele é uma decisão do leitor.
   ───────────────────────────────────────────────────────────────────────── */

/* ── a folha (Onda 3, §1) ────────────────────────────────────────────────
   O artigo virou objeto: `--papel` pousado sobre `--tela`, com sombra. Antes
   desta mudança o Leitor não tinha folha nenhuma — a tela inteira ERA o
   papel (`body { background: var(--papel) }`), e por isso o claro do Leitor
   nunca batia com o claro do Tabula, que sempre pintou uma mesa por baixo
   dos post-its. Os dois agora são vistas do mesmo mundo.

   **Sombra `--sombra-pousada`, não `--erguida`.** Os três degraus do núcleo
   modelam um objeto a alturas diferentes da mesa (ver o cabeçalho dos temas
   em `nucleo.css`); a folha não paira — ela está apoiada, é a mais rasa das
   três sombras que existe,
   a mesma que `.abas.seg .aba.ativa` já usa para "sobe do trilho, não do
   papel". Erguida ou alta fariam a folha parecer um cartão flutuando sobre
   a escrivaninha, não papel pousado nela.

   **`--respiro` é o espaço entre a coluna e a beirada da folha**, não a
   largura da folha em si — a coluna continua sendo `--measure`, sempre.
   `box-sizing: border-box` (reset do núcleo) faz a aritmética sozinha: ao
   somar `--respiro` duas vezes no `max-width` e usá-lo como `padding`, a
   ÁREA DE CONTEÚDO que sobra por dentro do padding é exatamente
   `--measure`, sem precisar redeclarar largura em `header`/`.prosa`/
   `footer`. `clamp` mantém o respiro generoso num monitor largo sem deixar
   a folha enorme, e mínimo (mas nunca zero) numa tela só um pouco maior que
   a coluna — abaixo de 900px o respiro desiste de vez (regra seguinte). */
.artigo {
  max-width: calc(var(--measure) + var(--respiro) * 2);
  /* Margem de baixo reduzida na L-71 pela mesma razão do `main`: a folga da
     barra fixa é do último elemento do fluxo, e agora o último é o `#versao`.
     Somadas, as duas dariam folga em dobro na rota de leitura — a única em
     que o `main` não tem padding próprio e a folha responde por ela. */
  margin: 1.6rem auto 1.5rem;
  padding: 2rem var(--respiro);
  background: var(--papel);
  border-radius: var(--raio);
  box-shadow: var(--sombra-pousada);
}
/* No escuro, sombra preta sobre mesa quase preta some — mesmo modo de falha
   que o post-it do Tabula documenta: `--papel` (#16171a) × `--tela`
   (#14171a) mede 1,004:1, e a camada mais forte de `--sombra-pousada`
   compõe #0a0c0d sobre a mesa, 1,090:1 — as duas cores próximas demais para
   o olho separar. Ali a borda volta a ser carga real (é a única pista que
   sobra de "isto é uma folha à parte"), então ela fica só neste tema, no
   mesmo token que o Tabula usa para o mesmo problema. */
[data-tema="escuro"] .artigo { border: 1px solid var(--papel-borda); }
/* Tela estreita: iPhone inteiro e a maioria dos iPads em retrato — todos
   menos o 12,9" Pro, que só ele sobra respiro real a 1024px (calculado com
   `--tamanho` padrão e largura "média": iPhone e iPad mini/9-10ª geração
   ficam de ponta a ponta MESMO SEM esta regra, porque `--measure` +
   2×`--respiro` já estoura a viewport sozinho; os de 11", 810–834px, é que
   sobrariam uma margem de mesa de 13–22px de cada lado — fina demais para
   ler como respiro deliberado, fina o bastante para ler como acidente de
   raio de canto brigando com a borda da tela). Uma margem de escrivaninha
   ali rouba exatamente a largura que este app existe para proteger. A
   folha vai de ponta a ponta — sem raio (não há beirada para arredondar
   quando a beirada é a própria tela) e sem margem lateral; o padding volta
   a ser o do `main` original, preservando o safe-area-inset que o resto do
   app usa. O vertical (margem de 1.6rem/barra-h e padding de 2rem) não
   muda: só a dimensão que competia com a coluna é que cede. */
@media (max-width: 900px) {
  .artigo {
    max-width: none;
    margin-left: 0; margin-right: 0;
    border-radius: 0;
    padding-left: max(1.1rem, env(safe-area-inset-left));
    padding-right: 1.1rem;
  }
}
.artigo > header { margin: 0 0 var(--space-block); }
.artigo h1 { font-size: 1.75em; line-height: 1.18; margin: 0 0 .35em; font-weight: 600;
  letter-spacing: -0.01em; text-wrap: balance; }
.artigo .meta { font-family: var(--sans); font-size: .8rem; color: var(--tinta-2); margin: 0; }

/* O botão "Ouvir" mora no CABEÇALHO, não no rodapé (ouvir é a primeira
   decisão ao abrir o artigo, não a última — antes dele só era alcançável
   depois de rolar o texto inteiro). `.btn.ouvir` e `.audio-leitura`
   continuam sendo as mesmas classes do Bloco J — só o
   respiro abaixo da `.meta` é próprio deste lugar, porque aqui não há mais
   o wrapper `.acoes` do rodapé para dar esse espaçamento. `display: inline-flex`
   evita que o botão estique para a largura da coluna, como um `<p>` faria. */
.artigo > header .btn.ouvir { display: inline-flex; margin-top: .9rem; }
/* E o `[hidden]` de volta, que o `display` acima derrubava.  (L-120)

   `botao.hidden = true` é o que tira o botão de cena quando a voz começa —
   o player nasce onde ele estava. Só que uma regra de autor com `display`
   vence o `[hidden] { display: none }` da folha do navegador, e o efeito era
   o botão «Tocar» ficando na tela ao lado do player durante a leitura
   inteira, contradizendo o próprio estado. Nenhum teste via: o JS punha o
   atributo certo e o markup estava certo — só o pixel estava errado.

   Sete outros lugares deste arquivo já trazem a guarda (`#acoes[hidden]`,
   `.audio-leitura[hidden]`, `#tempo-leitura[hidden]`…); esta era a que
   faltava, e apareceu na primeira renderização do bloco do lado. */
.artigo > header .btn.ouvir[hidden] { display: none; }
/* `.audio-leitura` já tem `margin-top: .8rem` na regra genérica mais abaixo —
   suficiente aqui também, porque ela nasce logo depois do botão (escondido)
   ou da `.meta`, nos dois casos com margem zero por cima. */
.artigo > header .sub[data-ouvir-aviso] { margin: .5rem 0 0; }

/* O corpo. Cada linha destas foi escolhida em 02 §2.4 e vale reler o porquê
   antes de mexer — em especial as duas primeiras. */
.prosa {
  font-optical-sizing: auto;         /* usa o eixo opsz das variáveis */
  text-wrap: pretty;                 /* sem órfãs nem linha final de 1 palavra */
  hyphens: auto;                     /* com lang="pt-BR" no <html> */
  -webkit-hyphens: auto;
  -webkit-hyphenate-limit-before: 3; -webkit-hyphenate-limit-after: 3;
  text-align: left;                  /* NUNCA justificado: abre rios de branco */
  font-variant-numeric: oldstyle-nums proportional-nums;
  font-kerning: normal;
  overflow-wrap: break-word;         /* URL de advisory não estoura a coluna */
}
.prosa > * { margin: 0 0 var(--space-para); }
.prosa h2, .prosa h3 { font-weight: 600; line-height: 1.25; margin: var(--space-block) 0 .4em; }
.prosa h2 { font-size: 1.28em; }
.prosa h3 { font-size: 1.1em; }
.prosa a { color: var(--acento); text-underline-offset: .18em; text-decoration-thickness: 1px; }

/* ── A nota de rodapé não pode sair da caixa da linha  (2026-09-01) ─────────
   Estas quatro declarações não são tipografia: são o conserto do «rastro
   vermelho» relatado no iPad, e mexer nos números reabre o defeito.

   ── O sintoma, e por que ele parecia ser de outro assunto ──────────────────
   Enquanto a voz lia, ficavam na página faixas finas órfãs — um pedaço na cor
   da palavra acesa, outro na cor da faixa da frase —, **sempre logo acima da
   linha que traz uma nota**. Medidas na captura: 4,5px de altura, e o pedaço
   colorido começando exatamente onde começa a palavra seguinte ao `[12]`.
   Parecia defeito de repintura do `::highlight()`, e o `leitura-falada.mjs` já
   carregava um conserto de 31/08 escrito sob essa suspeita (a "invalidação
   forçada"). Não era ali.

   ── A causa ───────────────────────────────────────────────────────────────
   `Range.getClientRects()` — que é **o retângulo que o `::highlight()` pinta**
   — devolve a caixa do TEXTO de cada fragmento inline: ascent + descent da
   fonte, e não a caixa da linha (medido: 30px fixos para as três entrelinhas,
   cujo `line-height` vai de 29,5 a 35,6px). Um `<sup>` na folha do navegador
   herda o `line-height` do parágrafo e sobe por `vertical-align: super`: o
   retângulo dele nascia **3,8 a 4,8px acima** do retângulo dos vizinhos de
   linha. O motor pintava o acompanhamento naquela faixa estendida e, ao
   despintar, invalidava só a caixa normal. A sobra ficava na página.

   Ou seja: a página pedia tinta fora da linha, e o defeito de repaint do
   WebKit era o segundo passo, não o primeiro. Tirado o pedido, não há sobra —
   e o conserto vale para qualquer motor, presente ou futuro.

   ── Os números, e por que são estes ────────────────────────────────────────
   Com fonte a `.7em`, o teto medido em 54 combinações (3 fontes de leitura × 3
   entrelinhas × 3 tamanhos, no Safari) é `.4em` de subida e ~`.07em` de
   descida. A folga é assimétrica porque a caixa do texto é: sobra muito
   ascent acima da baseline e quase nada de descent abaixo. Daí o `<sub>`
   descer pouco — o índice fica sutil, e é o preço de ele não deixar rastro na
   entrelinha de baixo. Os valores escolhidos ficam **abaixo** do teto:

     <sup>  .7em / +.35em  → sobra 0 nas 54     (teto: +.4em)
     <sub>  .7em / −.06em  → sobra 0 nas 54     (teto: ~−.07em)

   `web/test/interacao-rastro.mjs` mede as duas coisas: a sobra geométrica, em
   toda a matriz, e — por screenshot do Safari — a tinta órfã que ela produz.
   Um valor mais alto passa no olho e reprova lá. */
.prosa sup { font-size: .7em; vertical-align: .35em; }
.prosa sub { font-size: .7em; vertical-align: -.06em; }

/* ── A imagem continua `block`, e a razão foi MEDIDA  (05/09) ──────────────
   Ela é da mesma família do rótulo do callout: uma `<img>` em `display: block`
   dentro de um `<p>` COM TEXTO parte o parágrafo em blocos anônimos, e o
   WebKit deixa de pintar `::highlight()` no resto dele.

   `inline-block` conserta e cobra caro: um `<p>` com só a figura media 374px e
   passou a medir 463 (Safari, medido), porque a caixa de linha traz o strut —
   e isso empurraria TODA figura do acervo. O `:only-child` não separa os dois
   casos: ele conta elementos, e um `<p>` com imagem e texto tem a imagem como
   único filho-elemento.

   Então o conserto foi para a INGESTÃO, onde o caso ruim deixa de nascer:
   `paraHtml` separa a imagem do texto em parágrafos próprios
   (`markdown.mjs`, `imagemEmParagrafoProprio`). Com essa garantia na origem,
   `block` aqui não pode apagar realce nenhum — não há texto ao lado dela.
   Varredura do acervo em 05/09: 22 parágrafos com imagem, zero com texto
   junto, o que este passo torna invariante em vez de acaso. */
.prosa img { display: block; width: 100%; height: auto; border-radius: 4px; margin: var(--space-block) 0; }
/* --tinta, não --tinta-2: figcaption recebe data-bid (bids.mjs:48-51), logo é
   destacável, e os --hl-* foram calibrados para --tinta por cima — --tinta-2
   sob destaque reprovava em 9 das 12 combinações (Task 4/9). */
.prosa figcaption { font-family: var(--sans); font-size: .85em; color: var(--tinta); margin-top: -1.4em; }
.prosa blockquote { border-left: 2px solid var(--regra); padding-left: 1.2em; margin-left: 0; }
.prosa code { font-family: var(--mono); font-size: .88em; background: var(--papel-elev);
  padding: .1em .3em; border-radius: 3px; }
/* A cerca QUEBRA a linha, e não rola  (06/09, a pedido do dono)
   ─────────────────────────────────────────────────────────────────────────
   A barra horizontal esconde o fim da linha atrás de um gesto: quem lê um
   estudo no iPad não arrasta código, salta ele. Com a quebra, a linha longa
   continua na de baixo, alinhada com o começo do programa (o `padding-left`
   da calha vale para a continuação também), e a calha diz onde uma linha de
   verdade termina. O `overflow-x` fica como rede: uma tabela ASCII de
   `language-text` ainda pode não caber. */
.prosa pre { background: var(--papel-elev); padding: 1em; border-radius: 4px; overflow-x: auto;
  white-space: pre-wrap; overflow-wrap: anywhere; }
.prosa pre code { background: none; padding: 0; font-size: .88em; }

/* ── A matemática  (spec 44) ──────────────────────────────────────────────
   O servidor marca `span.matematica` e o KaTeX desenha dentro dele. Duas
   formas, decididas pelo DOM e não por campo: a fórmula que é o único filho do
   parágrafo é display (linha própria, centrada); a que divide o parágrafo com
   prosa fica na linha, no meio da frase.

   `inline-block` com `width: 100%`, NUNCA `block` — a mesma pedra da calha de
   números logo acima: um filho inline da prosa que vira bloco parte o `<p>` em
   blocos anônimos e o WebKit deixa de pintar `::highlight()` no resto dele. O
   parágrafo aqui é justamente um dos que a voz lê. Há guarda no
   `bimodal-css.test.mjs`.

   `overflow-x: auto` porque uma matriz do Cryptography and Network Security é
   mais larga que os 390px do iPhone: sem isto quem rola é a PÁGINA, e o app
   inteiro ganha barra horizontal por causa de um parágrafo. */
.prosa .matematica { overflow-x: auto; overflow-y: hidden; max-width: 100%; }
/* `[data-display]` é escrito pelo `renderizarMatematica`, e não por
   `:only-child`: o seletor conta ELEMENTOS e ignora o texto, então um
   parágrafo que TERMINA em fórmula casaria e a fórmula saltaria para o meio
   da linha. A régua é uma só, e mora no JS. */
.prosa .matematica[data-display] { display: inline-block; width: 100%;
  box-sizing: border-box; text-align: center; padding: .4em 0; }
/* A fórmula que não compilou fica como texto — feio, honesto, e é o que se
   copia para consertar. Monoespaçada para o LaTeX ficar legível. */
.prosa .formula-falhou { font-family: var(--mono, ui-monospace, monospace);
  font-size: .9em; opacity: .85; }

/* A calha de números. `--calha` é escrito pelo `numerarLinhas` conforme o
   total de linhas — dois dígitos num estudo, três num capítulo de livro. */
/* `inline-block` com `width: 100%`, nunca `block`: um filho inline da prosa
   que vira bloco parte o parágrafo em blocos anônimos e o WebKit deixa de
   pintar `::highlight()` no resto dele — o realce da voz sumiria dentro da
   cerca inteira, sem erro nenhum. É a lição de 05/09, e há guarda no
   `bimodal-css.test.mjs` que a cobra. */
.prosa pre > code.numerada { counter-reset: ln; }
.prosa pre > code.numerada > .ln { display: inline-block; width: 100%;
  box-sizing: border-box; position: relative;
  padding-left: calc(var(--calha, 2ch) + 1.4ch);
  /* A linha EM BRANCO de um programa é uma linha: sem altura mínima ela mede
     zero, e o número dela cai por cima do número da linha seguinte. Foi o que
     a captura mostrou e a medição de altura não pegava — ela olhava a linha
     mais alta, não a mais baixa. */
  min-height: 1.4em; min-height: 1lh; }
.prosa pre > code.numerada > .ln::before {
  counter-increment: ln; content: counter(ln);
  position: absolute; left: 0; top: 0; width: var(--calha, 2ch);
  text-align: right; color: var(--tinta-fraca);
  user-select: none; -webkit-user-select: none; }
/* A quebra de linha continua no texto do bloco — é a coordenada dos destaques
   — e sai do fluxo para não desenhar uma linha em branco a cada linha. */
.prosa pre .nl { position: absolute; width: 0; height: 0; overflow: hidden; }
.prosa ul, .prosa ol { padding-left: 1.4em; }
.prosa li { margin-bottom: calc(var(--space-para) / 2); }
/* --tinta, mesma regra do figcaption acima: `li` está em BLOCOS (bids.mjs) e
   é destacável — o marcador vive dentro do mesmo elemento que pode ganhar um
   --hl-* por baixo. */
.prosa li::marker { color: var(--tinta); }
.prosa table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums lining-nums;
  font-size: .92em; display: block; overflow-x: auto; }
.prosa th, .prosa td { text-align: left; padding: .45em .7em; border-bottom: 1px solid var(--regra); }
.prosa th { font-weight: 600; }
.prosa hr { border: 0; border-top: 1px solid var(--regra); margin: var(--space-block) 0; }

/* Rodapé: fonte, data, autor, clusters e as ações de estado. */
.artigo > footer { margin-top: calc(var(--space-block) * 1.5); padding-top: 1.2rem;
  border-top: 1px solid var(--regra); font-family: var(--sans); font-size: .84rem; }
.artigo > footer p { color: var(--tinta-2); margin: 0 0 .8rem; }
.artigo > footer a { color: var(--acento); }
/* O grupo dos três botões. É o MESMO wrapper nos dois lugares (rodapé do
   artigo e linha da lista) — o que muda é o gap e a margem, declarados por
   contexto logo abaixo e na seção dos redondos. */
.acoes { display: flex; align-items: center; gap: .4rem; }
.artigo > footer .acoes { flex-wrap: wrap; gap: .6rem; margin-top: 1rem; }

/* A barra de progresso que morava aqui (4px no topo, com marcos de meta em
   25·50·75%) virou a bolha `#progresso-flutuante` — ver a seção dela junto
   das irmãs da coluna flutuante, adiante. Duas encarnações no topo não
   bastaram: 2px quase subliminar, depois 4px em cor plena — e continuou
   difícil de ver, porque o topo é onde o olho NÃO está durante a leitura. */

/* Cromo que some ao rolar para baixo e volta ao rolar para cima — ou ao toque
   no texto (L-53b). A `.cabeca` não precisa de regra: ela está no fluxo e sai
   da tela sozinha, rolando junto com o que a empurrou. Quem precisa é a barra,
   que é fixa.

   **É na tela de artigo que isto conta**, e desde 2026-09-02 é só lá que
   acontece. A versão anterior desta regra não qualificava a rota e se apoiava
   numa premissa: «nas telas de serviço o conteúdo raramente passa da `folga`
   de 80px do `criarCromo`, então a barra fica onde está». A premissa é falsa
   — a inbox com nove artigos rola muitas telas —, e a D1 (navegação presente
   fora do texto, ausente dentro dele) valia por acidente de altura, não por
   desenho. O defeito ficou visível no Mac, onde a barra é a lateral de 216px:
   rolar a lista apagava a navegação inteira.

   O conserto é aqui e não no `criarCromo`: o atributo diz «a rolagem foi para
   baixo», que é verdade em qualquer tela, e o app.mjs já declara que a rota no
   `<body>` existe **para o CSS** decidir coisas assim. */
body[data-leitura][data-cromo="oculto"] #barra-nav { transform: translateY(100%); }

/* E no Mac, onde a mesma barra é a lateral de 216px, ela sai pelo LADO. A
   regra vive aqui, colada na irmã, porque é a ORDEM que a faz valer: as duas
   têm especificidade idêntica (`body[atributo][atributo] #id`), e `@media` não
   soma peso — de cima, ela perdia calada. Medido no Safari por
   `test/interacao-cromo.mjs`, que foi onde o defeito apareceu. */
@media (min-width: 1100px) and (pointer: fine) {
  body[data-leitura][data-cromo="oculto"] #barra-nav { transform: translateX(-100%); }
}

/* ── Ajustando um destaque: o cromo sai do caminho da sondagem (L-71) ───────
   Arrastar uma alça não move o intervalo por deslocamento — `ajuste.mover()`
   pergunta ao documento QUE TEXTO está sob o dedo (`caretRangeFromPoint`), e
   qualquer elemento por cima da prosa responde por si. A resposta não cai na
   prosa, o `mover` desiste em silêncio, e o destaque simplesmente não vai.

   Quatro alvos, e nenhum é folclore:
   - `#barra-nav`  faixa cheia, fixa embaixo — nasceu na L-66 e é a faixa morta
                   maior, bem onde o polegar arrasta;
   - `#caneta`     56px que a L-66 subiu para cima da barra, e que em tela
                   estreita cai dentro da coluna de leitura;
   - `#acoes`      z-60, ancorada 10px acima do trecho, em cima da bolinha da
                   `#alcaA`, que se desenha 18px acima da linha;
   - `.alca`       44px de alvo de toque, o mínimo — ela come os ~22px iniciais
                   do próprio gesto, e é por isso que ajustar de leve nunca
                   funcionou e puxar longe sempre funcionou.

   Desligar o hit-test da própria alça no meio do arraste é seguro porque o
   arraste **escuta no documento** desde a L-51 (ver o cabeçalho de ajuste.mjs):
   nenhum `pointermove` depende de acertar a alça. Quem repõe isto é o fim do
   gesto, nos dois caminhos — `soltar` e `sair`. */
/* A coluna INTEIRA, e não só o `#caneta` (Bloco J7): o argumento acima é sobre
   qualquer elemento fixo por cima da prosa, e a coluna passou de uma bolha a
   cinco. As outras quatro estavam de fora por idade, não por decisão — e são
   56px cada, empilhados exatamente na metade de baixo da tela, que é onde o
   polegar arrasta. */
body[data-ajustando] #barra-nav,
body[data-ajustando] #caneta,
body[data-ajustando] #ouvir-flutuante,
body[data-ajustando] #velocidade-flutuante,
body[data-ajustando] #velocidade-painel,
body[data-ajustando] #ajustes-flutuante,
body[data-ajustando] #perguntar-flutuante,
body[data-ajustando] #rolagem-flutuante,
/* A bolha do progresso entrou na lista na L-124, quando virou alvo. Enquanto
   era só mostrador ela se protegia sozinha, com `pointer-events: none`
   permanente — a mesma solução da pílula do tempo, que segue de fora. */
body[data-ajustando] #progresso-flutuante,
body[data-ajustando] #acoes,
/* O trilho de marcadores (28/08): o painel largo é coluna de grade ao LADO
   do texto e nunca precisou estar aqui; o trilho é sobreposição na beirada
   direita, e elemento por cima da prosa responde pelo caretRangeFromPoint. */
body[data-ajustando] #marginalia,
body[data-ajustando] .alca { pointer-events: none; }

/* Borda em --borda-controle (§2): `.btn` mora tanto na folha (`.acoes` do
   rodapé, fundo --papel) quanto dentro de sheets com fundo --papel-elev
   (#ajustes, #nota) — e aí o próprio fundo do botão É o mesmo --papel-elev
   do sheet, diferença zero. Nos dois lugares a borda é a única pista de que
   ali existe um controle. */
/* O `.btn` acompanha o `.redondo` (04/09): mesma família, mesmo material. Ele
   mora tanto na folha (o rodapé do artigo, fundo `--papel`) quanto dentro dos
   sheets (`#ajustes`, `#nota`, fundo `--papel-elev`) — e era JUSTAMENTE nos
   sheets que ele desaparecia, porque ali o fundo do botão e o do painel eram o
   mesmo `--papel-elev` e a borda fina fazia todo o trabalho sozinha. Em cromo,
   o controle se distingue da superfície em qualquer uma das duas. */
.btn { font-family: var(--sans); font-size: .82rem; color: var(--cromo-tinta);
  background: linear-gradient(180deg, var(--cromo-1), var(--cromo-2));
  border: 1px solid var(--cromo-borda); border-radius: 6px; padding: .38rem .7rem; cursor: pointer; }
.btn:hover, .btn:focus-visible { border-color: var(--cromo-acento); color: var(--cromo-acento); }
.btn[aria-pressed="true"] { border-color: var(--cromo-acento); color: var(--cromo-acento); }
.btn[disabled] { opacity: .5; cursor: default; }

/* Painel de ajustes: sheet inferior. Cinco controles, nada mais — cada opção
   a mais é uma decisão que o leitor toma em vez de ler (02 §4). */
#ajustes { position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
  background: var(--papel-elev); border-top: 1px solid var(--regra);
  /* aresta, não alta: o painel nasce da borda de baixo e não paira sobre
     nada — é oclusão de contato, não sombra projetada por --luz-x. --alta
     projeta para BAIXO (Y positivo) e caía para fora da tela aqui. */
  box-shadow: var(--sombra-aresta); padding: 1rem 1rem calc(1rem + env(safe-area-inset-bottom));
  /* .22s ease, revertido de --dur var(--curva) (Onda 3, correção): a adoção
     do token trocava duas coisas de uma vez, e só uma delas foi decidida — os
     40ms de duração são de fato imperceptíveis, mas a curva NÃO é a mesma:
     `--curva` (.2,.7,.3,1) chega a 90% do curso em ~85ms contra ~135ms do
     `ease` original, com o painel em 37% do curso aos 20ms onde `ease`
     mostrava 8%. Isso muda a sensação do gesto — o sheet passa a "saltar"
     em vez de deslizar —, e ninguém decidiu essa parte. Duração e curva são
     duas decisões separadas; adotar o token de duração não obriga a adotar
     a curva junto. */
  font-family: var(--sans); transform: translateY(101%); transition: transform .22s ease; }
#ajustes[data-aberto="sim"] { transform: none; }

/* ── Em tela larga o sheet vira CARTÃO flutuante  (revisão 2026-08-24) ──────
   Um sheet de aresta faz sentido no telefone, onde a borda de baixo é a mão.
   No iPad e no Mac ele virava uma faixa de 1024px — cromo do tamanho da tela
   para cinco decisões do tamanho de um cartão. Flutuando na medida do texto,
   o painel fica um OBJETO da mesma família do `#nota`/`#conversa`: papel
   elevado, borda, raio.

   A física da sombra muda junto, e de propósito: ancorado na aresta ele
   usava `--sombra-aresta` (oclusão de contato, Y para cima); descolado da
   borda ele paira, e o que paira projeta — `--sombra-erguida`, com a luz de
   `--luz-x`, como a pílula de ações. É a distinção que o núcleo documenta.

   O fechado desce `101% + 2rem`: o 101% sozinho deixava a beirada de cima
   do cartão espiando na base da tela, porque agora há 1rem de mesa entre
   ele e a borda. */
@media (min-width: 640px) {
  #ajustes {
    left: 0; right: 0; margin-inline: auto;
    width: min(46rem, calc(100% - 2rem));
    bottom: calc(1rem + env(safe-area-inset-bottom));
    padding: 1.15rem 1.3rem 1.3rem;
    border: 1px solid var(--papel-borda); border-top-color: var(--papel-borda);
    border-radius: var(--raio);
    box-shadow: var(--sombra-erguida);
    transform: translateY(calc(101% + 2rem));
  }
  #ajustes[data-aberto="sim"] { transform: none; }
}
/* ── O sumário  (L-124) ────────────────────────────────────────────────────
   Mesmo material e mesma física do `#ajustes` — sheet de aresta no telefone,
   cartão flutuante a partir de 640px — porque é a mesma família de painel, e
   inventar uma segunda gramática para o segundo sheet é como o cromo de um
   app começa a parecer costurado por duas pessoas.

   O que muda é a ALTURA: o de ajustes tem cinco grupos e nunca rola; este tem
   tantas linhas quanto o texto tiver seções, e um paper de trinta seções
   passaria da tela inteira. Daí o teto de 60vh com rolagem própria, e o
   `overscroll-behavior: contain` — sem ele, chegar ao fim da lista transfere
   o gesto para a prosa por baixo, e o leitor perde o lugar exatamente enquanto
   procura para onde ir.

   O painel abre à DIREITA no cartão, alinhado com a coluna de bolhas: ele
   nasce de uma delas, e um cartão centralizado faria o gesto perder a origem.
   No telefone continua de aresta a aresta, onde não há origem a perder. */
#sumario {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
  background: var(--papel-elev); border-top: 1px solid var(--regra);
  box-shadow: var(--sombra-aresta);
  padding: .9rem 1rem calc(1rem + env(safe-area-inset-bottom));
  font-family: var(--sans);
  max-height: 60vh; overscroll-behavior: contain;
  /* ── O SCROLL só existe com o painel ABERTO  (31/08) ────────────────────
     `overflow-y: auto` permanente deixava a barra de rolagem do painel
     pintada na tela DEPOIS de ele fechar — uma faixa vertical fina, do alto
     até 60vh, sobrevivendo ao `visibility: hidden`. No WebKit a barra overlay
     é composta à parte e não segue a visibilidade do dono; num livro de 180
     seções, que é onde a lista rola de verdade, ela ficava lá até o próximo
     repaint.
     `hidden` no fechado resolve na origem: barra que não existe não sobra. */
  overflow: hidden;
  transform: translateY(101%); transition: transform .22s ease, visibility 0s .22s;
  /* ── FECHADO É INVISÍVEL, e não «deslizado para fora»  (conserto de 31/08)
     O `#ajustes` pode contar só com o `translateY(101%)` porque nasce colado
     na borda de baixo: descer a própria altura o tira da tela. Este painel
     não — a partir de 640px ele é um cartão ancorado no MEIO da coluna, e
     101% da altura dele o move oitenta pixels para baixo, ainda em cena.
     Foi assim que o painel VAZIO apareceu na inbox: uma caixa branca no canto
     direito, sem campo, sem explicação. `visibility` (e não `display`) para
     que a transição continue existindo; o atraso de .22s a segura até o fim
     do deslize. */
  visibility: hidden;
}
#sumario[data-aberto="sim"] {
  transform: none; visibility: visible; transition-delay: 0s;
  overflow-y: auto;
}

/* Fora do artigo não há texto que tenha sumário — mesma regra da bolha que o
   abre, e das cinco bolhas irmãs. `data-rota`, e não `hidden`: nenhuma tela o
   revela, então nenhuma teria de recolhê-lo. */
body:not([data-leitura]) #sumario { display: none; }

@media (min-width: 640px) {
  #sumario {
    /* AO LADO da coluna de bolhas, nunca por cima: o painel nasce de uma
       delas, e cobrir as outras seis tira da tela justamente os controles que
       o leitor pode querer em seguida (pausar a voz, ajustar o texto). O
       recuo é o diâmetro da bolha mais a folga do degrau. */
    left: auto; right: calc(var(--capsula-x) + var(--capsula-l) + .6rem);
    width: min(22rem, calc(100vw - 6rem));
    /* Alinhado pelo item que o abre — o anel do progresso —, e crescendo para
       cima. `--y-progresso` é a altura dele a partir da base da pilha. */
    bottom: calc(var(--pilha-y) + var(--y-progresso));
    padding: .9rem 1rem 1rem;
    border: 1px solid var(--papel-borda); border-radius: var(--raio);
    box-shadow: var(--sombra-erguida);
    transform: translateY(1rem);
    /* ── O TETO é o espaço acima da ÂNCORA, não uma fração da tela  (31/08)
       O painel cresce para cima a partir da bolha, que está a seis degraus do
       rodapé. `max-height: 60vh` mede a tela inteira e ignora isso: no iPad,
       60vh mais a altura da âncora passava do topo, e os primeiros itens do
       sumário ficavam cortados acima da borda — invisíveis e inalcançáveis,
       porque nem rolando se chega ao que está fora da tela.

       A conta é a mesma da âncora, e por isso não desafina quando o degrau
       muda: altura da janela menos a distância até a bolha, menos uma folga
       de respiro. `dvh` porque no Safari do iPad a barra de endereço entra e
       sai da conta de `vh`; o `vh` fica como reserva para quem não conhece a
       unidade nova. */
    max-height: calc(100vh - (var(--pilha-y) + var(--y-progresso)) - 1.5rem);
    max-height: calc(100dvh - (var(--pilha-y) + var(--y-progresso)) - 1.5rem);
  }
  #sumario[data-aberto="sim"] { transform: none; }
}

.sumario-lista { list-style: none; margin: 0; padding: 0; }

/* O recuo por profundidade, e o teto de três níveis: `h1`→`h4` dão quatro
   degraus, e o quarto recuo já come metade da largura útil de um telefone.
   O `data-profundidade` chega da `extrairSecoes` já limitado a 3. */
.sumario-lista li[data-profundidade="1"] { padding-left: .9rem; }
.sumario-lista li[data-profundidade="2"] { padding-left: 1.8rem; }
.sumario-lista li[data-profundidade="3"] { padding-left: 2.7rem; }

/* A linha inteira é o alvo — 44px de altura mínima, o alvo de toque do resto
   do app. Alinhamento ao TOPO (e não centralizado): título de duas linhas com
   a marca centralizada faz o `▸` flutuar no meio do texto em vez de apontar
   para o começo dele. */
.sumario-lista button {
  display: flex; align-items: flex-start; gap: .5rem;
  width: 100%; min-height: var(--alvo); padding: .45rem .3rem;
  border: 0; background: none; cursor: pointer; text-align: left;
  font-family: var(--sans); font-size: .92rem; line-height: 1.35;
  color: var(--tinta-2); border-radius: var(--raio-p);
}
.sumario-lista .marca {
  flex: 0 0 1rem; text-align: center; color: var(--tenue);
  /* A marca ocupa a calha MESMO vazia (a seção adiante não tem glifo): sem a
     largura fixa, as linhas sem marca começariam 1rem à esquerda das outras e
     a lista pareceria desalinhada em vez de hierárquica. */
  line-height: 1.35;
}

/* Já passou por aqui: mais claro, nunca riscado. Riscar diria «resolvido», e
   o que se leu continua sendo o que se pode reler. */
.sumario-lista li[data-estado="passou"] button { color: var(--tenue); }
.sumario-lista li[data-estado="passou"] .marca { color: var(--progresso); }

/* Você está aqui. Peso e cor plena, mais a barra de acento à esquerda: é a
   única linha que o olho precisa achar sem ler, porque é a resposta à
   pergunta que fez o painel ser aberto. */
.sumario-lista li[data-estado="aqui"] button {
  color: var(--tinta); font-weight: 600;
  background: color-mix(in srgb, var(--progresso) 10%, transparent);
}
.sumario-lista li[data-estado="aqui"] .marca { color: var(--progresso); }

/* ── O painel de ajustes  (L-73) ───────────────────────────────────────────
   Antes: cinco fileiras de pílulas de texto idênticas, presas a uma calha de
   rótulos de 5.5rem, deixando metade da largura vazia à direita. Num app cuja
   razão de existir é a tipografia, era o único lugar que traía a premissa.

   Agora: uma grade de dois campos que ocupa a medida inteira, e cada opção é
   uma AMOSTRA do próprio efeito. A ordem do DOM não mudou — fonte, tamanho,
   entrelinha, largura, tema —, então a `fonte` ocupa a faixa inteira e os
   outros quatro caem em pares, sem `grid-area` nenhum. */
#ajustes .grade {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: .9rem 1.4rem; max-width: var(--measure); margin-inline: auto;
}
#ajustes .grupo[data-grupo="fonte"] { grid-column: 1 / -1; }

/* No telefone a grade vira uma coluna. Em duas, cada grupo fica com metade da
   medida para três opções — e "Compacta" numa caixa de ~55px quebra a palavra
   ou a corta. Empilhado, cada fileira tem a largura inteira, e a única perda é
   rolagem que este painel não tem (ele cresce para cima, e são cinco grupos).
   Mesmo corte da linha da lista, pelo mesmo motivo. */
@media (max-width: 480px) {
  #ajustes .grade { grid-template-columns: 1fr; gap: .75rem; }
}

/* O rótulo vira sobrancelha: a mesma voz do `.eyebrow` da lista e do
   `.rotulo-temas`. Em cima da fileira, e não ao lado, é o que devolve a
   largura que a calha comia. */
#ajustes .rotulo {
  display: block; font-size: .62rem; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--tenue); margin: 0 0 .4rem .1rem;
}
#ajustes .opcoes { display: flex; gap: .4rem; }

/* Um só botão para as cinco linhas. `flex: 1` e não largura fixa: as três
   opções dividem a coluna em partes iguais, e a fileira acaba onde a medida
   acaba — é isso que fecha o vazio à direita. */
#ajustes .opcao {
  flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: .3rem;
  /* Altura ÚNICA para os cinco grupos, e não `min-height: var(--alvo)`: as
     opções com glifo e palavra chegam a ~54px sozinhas, as de só glifo param
     nos 44px do alvo, e as duas colunas da grade saíam desencontradas — o
     `A−` visivelmente mais baixo que o `Compacta` ao lado. Uma altura fixa
     alinha as fileiras e continua acima do alvo mínimo. */
  min-height: 3.4rem; padding: .5rem .3rem;
  border: 1px solid var(--borda-controle); border-radius: var(--raio-p);
  background: none; color: var(--tinta); font-family: var(--sans);
  cursor: pointer; overflow: hidden;
}
#ajustes .opcao:hover, #ajustes .opcao:focus-visible {
  border-color: var(--acento); color: var(--acento);
}
#ajustes .opcao[disabled] { opacity: .4; cursor: default; }
#ajustes .opcao[disabled]:hover { border-color: var(--borda-controle); color: var(--tinta); }

/* Escolhido. Mesma língua do `[aria-pressed]` dos botões de estado (L-70):
   tinta, borda e um fundo tingido — três pistas, não uma. */
#ajustes .opcao[aria-pressed="true"] {
  color: var(--acento); border-color: var(--acento);
  background: color-mix(in srgb, var(--acento) 12%, transparent);
}
#ajustes .nome { font-size: .68rem; line-height: 1; color: inherit; }

/* A fonte se apresenta na própria fonte — a amostra mais óbvia das cinco, e a
   que a versão anterior deixava passar: os três nomes vinham no mesmo sans da
   interface, então escolher "Source Serif" era escolher no escuro. */
/* ── O espécimen  (revisão 2026-08-24) ─────────────────────────────────────
   Só o nome na própria face era amostra tímida: em ~16px, Literata e Source
   Serif são duas serifas que se distinguem por espremer os olhos. O "Ag" —
   o par clássico de espécimen de fundição, uma caixa-alta de haste e uma
   minúscula de bojo e descendente — mostra o desenho da face num tamanho em
   que a diferença é visível de relance, e o nome desce para rótulo.

   O "Ag" entra por `::before`, NÃO por markup, e isso é deliberado: o
   pseudo-elemento herda a família de `[data-face]` sozinho, o leitor de
   tela não anuncia um "Ag" sem sentido (o `aria-label` do botão já diz
   "Fonte: Literata"), e o contrato que os testes cravam — nenhum `.nome`
   dentro de `.am-fonte`, a palavra é a amostra — continua verdadeiro
   letra a letra. */
#ajustes .am-fonte {
  display: flex; flex-direction: column; align-items: center; gap: .42rem;
  font-size: .7rem; line-height: 1;
}
#ajustes .am-fonte::before { content: "Ag"; font-size: 1.7rem; line-height: 1; }
#ajustes .grupo[data-grupo="fonte"] .opcao { min-height: 4.7rem; }
#ajustes .am-fonte[data-face="literata"]     { font-family: var(--serif); }
#ajustes .am-fonte[data-face="source-serif"] { font-family: var(--serif-leitura); }
#ajustes .am-fonte[data-face="inter"]        { font-family: var(--sans); }
#ajustes .am-fonte[data-face="charter"]      { font-family: var(--serif-charter); }

/* Entrelinha: três filetes, com o vão do valor. A caixa tem altura fixa para
   que o botão não mude de tamanho entre as opções — o que muda é o ar. */
#ajustes .am-linhas {
  display: flex; flex-direction: column; justify-content: center;
  width: 1.6rem; height: .9rem;
}
#ajustes .am-linhas i { height: 1px; background: currentColor; opacity: .75; }
#ajustes [data-valor="compacta"] .am-linhas { gap: 2px; }
#ajustes [data-valor="normal"]   .am-linhas { gap: 4px; }
#ajustes [data-valor="arejada"]  .am-linhas { gap: 6px; }

/* Largura: a coluna dentro da página. A caixa é a página, o filete é o texto,
   e é a razão de a caixa existir — sem a moldura de referência, três filetes
   soltos de larguras parecidas não dizem "estreita" nem "larga", dizem só
   "filete". A moldura vem em `--regra` e não em `currentColor` para não
   competir com o filete, que é o que muda. */
#ajustes .am-largura {
  display: flex; align-items: center; justify-content: center;
  width: 1.9rem; height: 1.05rem;
  /* Derivada de `currentColor` e não de `--regra`: em `--regra` a moldura
     sumia no sépia, e uma moldura quase invisível é pior que nenhuma — lê
     como sujeira, não como página. A 32% ela fica claramente presente e
     ainda assim atrás do filete, que é o que carrega a informação. */
  border: 1px solid color-mix(in srgb, currentColor 32%, transparent);
  border-radius: 2px;
}
#ajustes .am-largura i { height: 2px; background: currentColor; opacity: .8; }
#ajustes [data-valor="estreita"] .am-largura i { width: 30%; }
#ajustes [data-valor="media"]    .am-largura i { width: 58%; }
#ajustes [data-valor="larga"]    .am-largura i { width: 88%; }

/* Tema: o papel e a tinta daquele tema, literais. São as únicas cores fixas
   do arquivo, e por isso mesmo: um token resolveria para o tema CORRENTE, e
   a amostra existe para mostrar um tema em que ainda não se está. Os valores
   saem de `[data-tema]` no núcleo — `--papel` e `--tinta` de cada um. */
#ajustes .am-tema {
  display: flex; align-items: center; justify-content: center;
  width: 1.6rem; height: 1.15rem; border-radius: 3px;
  border: 1px solid var(--regra);
  font-family: var(--serif); font-size: .72rem; line-height: 1;
}
#ajustes .am-tema[data-t="claro"]  { background: #faf8f4; color: #22211d; }
#ajustes .am-tema[data-t="sepia"]  { background: #f3e8da; color: #2e2519; }
#ajustes .am-tema[data-t="escuro"] { background: #16171a; color: #e4e2dd; }
/* O auto é metade e metade — e as duas metades são as que ELE produz: sépia de
   dia, escuro de noite. Sem o «Aa», porque letra nenhuma é legível sobre a
   divisa e o nome embaixo já diz o que é. */
#ajustes .am-tema[data-t="auto"] {
  background: linear-gradient(105deg, #f3e8da 50%, #16171a 50%);
  color: transparent;
}

/* ── O passo do tamanho é UM controle, não três coisas soltas ──────────────
   Na primeira volta eram dois botões com borda e um punhado de bolinhas
   flutuando no meio — três objetos onde há uma decisão só, e o único grupo do
   painel que não parecia um grupo. A moldura passa para a fileira e os botões
   ficam nus por dentro, separados por filete: um estepe, como o `A− A+` de
   qualquer leitor. */
#ajustes .grupo[data-grupo="tamanho"] .opcoes {
  gap: 0; border: 1px solid var(--borda-controle);
  border-radius: var(--raio-p); overflow: hidden;
}
#ajustes .passo-btn {
  flex: none; width: 3.2rem; font-size: .95rem;
  border: 0; border-radius: 0; min-height: 3.4rem;
}
#ajustes .passo-btn:first-child { border-right: 1px solid var(--regra); }
#ajustes .passo-btn:last-child  { border-left: 1px solid var(--regra); }
/* Sem o realce de borda dos outros: aqui a borda é da fileira, e pintá-la a
   partir de um botão de dentro acenderia o controle inteiro no hover de meia
   dúzia de pixels. */
#ajustes .passo-btn:hover, #ajustes .passo-btn:focus-visible { border-color: var(--regra); }

/* As sete posições de 02 §4, que o `0` cru nunca mostrou. */
#ajustes .passo {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: .32rem;
}
/* 8px e não 6: o medidor existe para ser CONTADO de relance — "estou no
   quarto de sete" —, e a 6px distinguir cheia de vazia exigia parar e olhar,
   que é justamente o que um medidor deve poupar. */
#ajustes .passo i {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  border: 1px solid var(--borda-controle);
}
#ajustes .passo i.on { background: var(--acento); border-color: var(--acento); }

/* ── destaque (L-49, refeito na spec 45) ───────────────────────────────────
   O texto NÃO muda de cor. Quem lê marcou o trecho, não pediu outra fonte.

   ── O `<mark>` saiu daqui, e a razão é o parágrafo inteiro ─────────────────

   Até 10/09 o destaque era `<mark class="leitor-hl">` no DOM, com
   `padding: .08em 0` para fechar o vão entre as linhas. A nota que morava aqui
   contava metade da história: em 02/09 tirou-se o `box-decoration-break:
   clone` porque ele "fazia o WebKit abandonar o `text-wrap: pretty` do
   parágrafo inteiro". Estava certo, e era metade — **o elemento inline, e não
   a decoração dele, é o que muda o insumo do `pretty`**, que no WebKit é
   otimização de parágrafo e não de linha.

   Medido no Safari 26.6.2 (`interacao-quebras.mjs`): com `<mark>`, 14 de 360
   combinações de fonte × largura × espaçamento × corpo × posição da marca
   remaquetam o parágrafo; num caso ele sai byte a byte igual ao layout
   guloso. Um `<span>` sem estilo nenhum faz o mesmo, e trocar o `text-wrap`
   não resolve — com o guloso ainda são 8/360, e a órfã volta em 8 de 81
   perfis. O relato que fechou o caso: «quando faz uma marcação as vezes muda
   a disposição do texto. fica ruim».

   Marcar um trecho não pode remaquetar a página que se está lendo. O pigmento
   passou à Custom Highlight API, que pinta sem nó nenhum — a mesma peça que a
   voz usa desde a spec 11, e o `pretty` fica intocado.

   ── O que se perdeu, e o que não se perdeu ────────────────────────────────

   `::highlight()` aceita cor, `text-decoration` e sombra — não aceita padding
   nem raio. Perdeu-se: os `.08em` verticais e os 2px de canto. **Não** se
   perdeu o bloco contínuo, que era o medo: capturado lado a lado, o `<mark>`
   pinta 137px de faixa contínua e o highlight 134px — os 3px são o padding, e
   não há listra entre as linhas.

   `opacity` continua fora daqui, e pela razão de sempre: ela apagaria o texto
   junto com o fundo. Marcação mais fraca no escuro é propriedade da COR, e
   vive nos tokens do tema.

   Quem pinta cada nome é `pigmento.mjs`; a lista dos nomes é `NOMES` lá.
   ───────────────────────────────────────────────────────────────────────── */
::highlight(destaque-amarelo) { background-color: var(--hl-amarelo); }
::highlight(destaque-roxo)    { background-color: var(--hl-roxo); }
::highlight(destaque-rosa)    { background-color: var(--hl-rosa); }
::highlight(destaque-azul)    { background-color: var(--hl-azul); }

/* ── O destaque que tem nota  (L-51, refeito na spec 45) ───────────────────
   Era uma bolinha de 4px na ÚLTIMA marca do destaque, por `::after`. Sem
   elemento não há pseudo-elemento, e a informação — «este trecho tem nota
   escrita» — passa a ser dita pelo sublinhado pontilhado do trecho inteiro.

   A troca preserva as três decisões da L-51 e melhora uma: continua havendo um
   sinal no CORPO (nota que ninguém vê é nota perdida), continua sendo um sinal
   só por destaque (a bolinha em cada fragmento dizia três vezes o mesmo fato),
   continua fora da margem (indicador de margem marca o parágrafo, e o destaque
   é de um trecho) — e agora o sinal cobre exatamente o trecho anotado, em vez
   de pousar no fim dele.

   `--tinta-2` e não o acento: a nota é fato registrado, não chamado de ação. */
::highlight(destaque-amarelo-nota),
::highlight(destaque-roxo-nota),
::highlight(destaque-rosa-nota),
::highlight(destaque-azul-nota) {
  text-decoration: underline dotted var(--tinta-2);
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
}
::highlight(destaque-amarelo-nota) { background-color: var(--hl-amarelo); }
::highlight(destaque-roxo-nota)    { background-color: var(--hl-roxo); }
::highlight(destaque-rosa-nota)    { background-color: var(--hl-rosa); }
::highlight(destaque-azul-nota)    { background-color: var(--hl-azul); }

/* ── A frase que a voz está lendo  (Bloco J, spec 11 §6) ────────────────────
   Pintada pela Custom Highlight API (`leitura-falada.mjs`), que **não toca
   no DOM** — só por isso ela convive com os quatro `<mark>` acima sem que um
   apague o outro: um destaque de leitura em `<mark>` morreria na primeira
   repintura do motor (`repintar()` reescreve o `innerHTML` do bloco inteiro).

   O tom é deliberadamente MAIS FRACO que qualquer `--hl-*`: aqueles são
   pigmento opaco (uma decisão que fica na página); este é acompanhamento
   passageiro, que desliga sozinho quando a frase muda. `var(--leitura)` a
   12% no claro e no sépia — abaixo dos 14–16% que este arquivo já usa para
   tingir um ESTADO (`.acao-estado[aria-pressed]`, `.armado`) — e não um
   `--hl-*`: usar a família do destaque faria o olho ler "isto é um destaque
   marcado", que é exatamente a confusão que a §6 da spec pede para evitar.

   2026-08-26 — deixou de ser `var(--acento)` a 12% cravado. A cor veio para a
   família própria e a força virou token por tema; as duas razões estão na nota
   "── O acompanhamento da voz saiu do `--acento`" lá em cima. Uma regra só
   continua servindo aos três temas — só que agora respondendo a tokens que
   sabem em qual tema estão. */
::highlight(leitura) {
  background-color: color-mix(in srgb, var(--leitura) var(--leitura-forca), transparent);
}

/* ── A palavra que a voz está dizendo AGORA  (Bloco J2, spec 11) ────────────
   Segundo `Highlight`, registrado sob o nome `leitura-palavra` pelo
   `leitura-falada.mjs`, e ele acende POR DENTRO da faixa de cima — os dois ao
   mesmo tempo, sempre, porque respondem a perguntas diferentes (a faixa diz
   onde estou no texto; a palavra, o que está sendo dito). Daí as duas
   exigências que fixam esta regra:

   1. **Mais forte que a faixa, sem margem de dúvida.** A faixa é `--leitura`
      enfraquecida pela força do tema: 1,25:1 no claro, 1,25:1 no sépia e
      1,46:1 no escuro contra a página. A palavra é a cor CHEIA — 8,41:1 no
      claro, 8,18:1 no sépia, 7,91:1 no escuro. Não é um degrau a mais de
      intensidade, é outra ordem de grandeza, e é o que faz o olho achar a
      palavra dentro da faixa sem procurar. A WCAG 1.4.11 pede 3:1 para realce
      não-textual; os três passam com folga de 2,6×.

   2. **Nunca confundível com marcação da Pencil.** A cor ser outra não bastava
      como argumento, embora também seja verdade (`--leitura` fica a 4,68–6,30:1
      de qualquer `--hl-*`). O que de fato separa as duas coisas é o MECANISMO,
      e ele já está escrito três regras acima: a marcação **não muda a cor do
      texto** — "quem lê marcou o trecho, não pediu outra fonte". A voz inverte:
      o papel sobe para cima da cor. Marcação é pigmento POR BAIXO da letra,
      que fica na página; a voz passando é a letra vestindo outra cor por um
      instante. São gestos visualmente distintos antes de serem cores
      distintas, e o leitor não precisa comparar matiz para saber qual é qual.

      Desde 26/08 há uma terceira separação, e ela é de PALETA: a voz é
      acromática nos três temas e a marcação é o único pigmento saturado da
      página. Ver a nota da família lá em cima.

   `--sobre-leitura`, e não `--tinta`: no escuro a cor é o cinza-osso CLARO, e
   tinta clara por cima dela daria ~1,2:1. O token existe exatamente para essa
   pergunta ("quem escreve sobre a cor pergunta ao token") e responde certo
   nos três temas — 8,92 · 9,89 · 7,91:1.

   Só `background-color` e `color` porque `::highlight()` aceita um
   subconjunto pequeno de propriedades: `border`, `padding` e `transform`
   seriam ignorados **em silêncio**. Registrado para quem vier tentar
   arredondar o canto daqui e concluir que o navegador está quebrado. */
/* ── A palavra acesa volta ao acento  (2026-09-01, prancha 1i) ─────────────
   «A palavra acende na brasa», e ela acende.

   O caminho até aqui vale registro, porque o erro foi de INSTRUMENTO. A nota
   de 26/08 acima tirou a voz do acento por uma colisão real: em 21/08 o acento
   do escuro virou púrpura `#c19ae6`, a 6,2° do `--hl-roxo` `#42305c`, e três
   coisas caíram na mesma família de matiz naquele tema. O guarda que nasceu
   dali mede **matiz ou croma** — e recusou a brasa, porque ela fica a 27,9° do
   marca-texto no escuro e a 29,5° no claro.

   Só que matiz não é o que separa este par. Luminância é:

     escuro   voz #f39d7a × pigmento #463911 →  5,35:1
     claro    voz #832f0d × pigmento #eed88a →  6,24:1

   E há uma diferença estrutural entre 21/08 e hoje que o número sozinho não
   conta: naquela rodada a BANDA e a palavra eram as duas do acento, então um
   pigmento na mesma família fazia três coisas rimarem. Hoje a banda é
   `--leitura`, neutra — sobram duas, e elas se separam por valor.

   Por isso o guarda foi estendido, e não dispensado: ele passa a aceitar
   separação por luminância **desde que a banda continue neutra**. Com essa
   condição ele segue reprovando o caso de 21/08, que tinha 4,99:1 de
   luminância e colidia mesmo assim — luminância sozinha nunca o teria pego. */
::highlight(leitura-palavra) {
  background-color: var(--acento);
  color: var(--sobre-acento);
}

/* ── Régua de linha  (Bloco J2, `data-regua`) ───────────────────────────────
   CHI 2023, "Digital Reading Rulers": +86 palavras/min em média, com ganho
   maior entre leitores disléxicos, e entre os estilos testados o preferido foi
   o *Lightbox* — escurecer tudo MENOS a linha corrente, em vez de sublinhar
   ou emoldurar a linha. É o que está implementado aqui.

   ── A técnica, e por que não são dois retângulos ───────────────────────────
   O véu é um `box-shadow` de espalhamento 100vmax no PRÓPRIO elemento da
   faixa: a sombra cobre a tela inteira e o elemento recorta o próprio buraco.
   A alternativa óbvia — uma div acima e outra abaixo — custa dois elementos a
   posicionar em sincronia e reintroduz, em dobro, o problema que a linha
   seguinte resolve. Uma caixa, uma sombra, nenhum retângulo por cima do texto.

   ── `pointer-events: none` é requisito, não higiene ────────────────────────
   A 14 §4.2 registra a regra em letra de forma: o que não recebe toque não tem
   como roubar o `caretRangeFromPoint`. Um elemento fixo sobre a prosa SEM esta
   linha responde ao hit-test no lugar do texto, e o traço da Pencil passa a
   marcar nada — reprovando o critério de aceite do projeto ("20 destaques
   seguidos sem um traço errado"). A régua fica por cima da coluna inteira
   enquanto o áudio toca: sem isto, ela é o pior infrator que este app já teve.

   ── O alpha do véu muda por tema, e a razão foi medida ──────────────────────
   O lightbox funciona por caminhos OPOSTOS no claro e no escuro, e isso só
   aparece quando se mede em vez de copiar o número:
   · claro e sépia — o véu escurece o PAPEL (1,98:1 e 1,80:1 contra a faixa) e
     quase não toca no texto, que já era escuro (1,10:1 e 1,02:1). A faixa é
     que brilha. O texto de fora segue perfeitamente legível, a 8,49:1 e
     7,20:1 sobre o próprio fundo velado: recuar não é apagar, e o leitor
     ainda enxerga o parágrafo em volta.
   · escuro — não há para onde escurecer um papel que já é `#16171a`: o fundo
     mede 1,10:1 velado, ou seja, nada. Quem recua é o TEXTO — `--tinta` clara
     sob 55% de preto cai 4,44:1, indo de 16,5:1 contra a página para 3,45:1.
     Mesmo efeito, outro mecanismo. Por isso o alpha do escuro é o dobro do
     dos claros, e não um descuido a "uniformizar" um dia.

   O sépia usa preto QUENTE (`#3c280a`, o mesmo pigmento das sombras do sépia
   no núcleo): preto puro sobre papel amarelado sai cinza e frio, e a página
   inteira trocaria de temperatura fora da faixa.

   `--veu` mora aqui, e não no bloco de tema lá em cima, porque tem um único
   consumidor e porque a razão dos três valores é uma coisa só — separá-los
   deixaria três números órfãos da conta que os produziu. */
[data-tema="claro"]  { --veu: rgba(0,0,0,.28); }
[data-tema="sepia"]  { --veu: rgba(60,40,10,.30); }
[data-tema="escuro"] { --veu: rgba(0,0,0,.55); }

#regua {
  position: fixed; left: 0; right: 0;
  pointer-events: none;
  box-shadow: 0 0 0 100vmax var(--veu);
  /* Acima da prosa e ABAIXO de todo o cromo — a barra (40), o tempo (44), o
     botão da caneta (45/46), as ações (60). Velar a própria interface faria o
     app parecer desligado toda vez que o áudio começasse. */
  z-index: 30;
  /* `top` e `height` são do JS, e não por preguiça de CSS: linha não é
     elemento. Só o retângulo do `Range` da palavra sabe onde a linha caiu
     depois que fonte, tamanho, entrelinha e largura do leitor foram
     aplicados. */
  display: none;
  transition: top var(--dur) var(--curva);
}

/* Acesa só sob os dois valores que ligam a régua, e só quando o JS não a
   escondeu. É cinto E suspensório de propósito: `nao` é o padrão e custa
   `display: none` — nem sombra, nem camada de composição, nem pintura —, e o
   `:not([hidden])` garante que ela não fique acesa sobre um artigo parado. O
   `esconderRegua()` do `leitura-falada.mjs` a apaga quando o áudio termina;
   se um dia ele falhar, o pior caso vira uma régua esquecida na última linha
   lida, e não uma página velada sem áudio nenhum. Cada um dos dois já
   bastaria; nenhum dos dois custa. */
[data-regua="uma"] #regua:not([hidden]),
[data-regua="tres"] #regua:not([hidden]) { display: block; }

/* O véu de três linhas tinha opacidade própria (.72, "a faixa larga já dá
   contexto") e ela SAIU em 27/08, a pedido do Yuri: o tom deve ser o mesmo
   nas duas réguas. O argumento que a derrubou é de percepção — a troca de tom
   era o único efeito instantâneo de mudar a régua (a altura vinha de uma
   cópia que só o preparo escrevia, defeito consertado no mesmo dia), então o
   véu mais fraco lia-se como "mudou alguma coisa, mas não o que pedi". */

/* A régua salta de linha em linha, e o salto É o movimento: sem transição ela
   pisca de posição, com ela o olho é conduzido. Quem pediu menos movimento não
   pediu menos régua — pediu o corte seco, que é o que fica. */
@media (prefers-reduced-motion: reduce) {
  #regua { transition: none; }
}

/* ── As duas amostras do painel  (Bloco J2) ─────────────────────────────────
   Ficam aqui, e não junto das outras cinco lá em cima, pela mesma razão que
   pôs `.am-marg` no bloco da marginália: o desenho de uma amostra é
   consequência do que a opção faz, e as duas mudam pelo mesmo motivo.

   A régua repete a gramática de `.am-linhas` — filetes numa caixa de altura
   fixa —, com a diferença que carrega a informação: aqui o que muda não é o
   vão entre os filetes, é **qual deles está aceso e quanto a caixa escurece**.
   É o lightbox em 15px, e é o único jeito de "Uma linha" e "Três linhas"
   dizerem algo antes de o leitor ligar o áudio e ver na página.

   O espaçamento se mostra em si mesmo, como a fonte faz: `abc` na medida da
   opção. Sem isso, "Arejado" é uma palavra sobre uma palavra. */
#ajustes .am-regua {
  display: flex; flex-direction: column; justify-content: center; gap: 3px;
  width: 1.6rem; height: 1.05rem; padding: 0 2px; border-radius: 2px;
}
#ajustes .am-regua i { height: 1px; background: currentColor; opacity: .16; }
/* Sem régua: os três filetes iguais, e nenhum véu — a página como está hoje. */
#ajustes .am-regua[data-r="nao"] i { opacity: .7; }
/* O véu da amostra vem de `currentColor` e não de `--veu`: o botão herda a
   tinta do estado (e o acento quando escolhido), então a amostra acompanha o
   controle em vez de destoar dele. `--veu` é preto, e preto dentro de um botão
   aceso em acento leria como sujeira. */
#ajustes .am-regua[data-r="uma"] {
  background: color-mix(in srgb, currentColor 20%, transparent);
}
#ajustes .am-regua[data-r="uma"] i:nth-child(2) { opacity: 1; }
/* Três linhas: a faixa toma a caixa inteira, e o véu é mais fraco — a mesma
   relação que `[data-regua="tres"] #regua { opacity: .72 }` tem na página. */
#ajustes .am-regua[data-r="tres"] {
  background: color-mix(in srgb, currentColor 12%, transparent);
}
#ajustes .am-regua[data-r="tres"] i { opacity: .95; }

#ajustes .am-espaco { font-family: var(--corpo, var(--serif)); font-size: 1rem; line-height: 1.15; }
#ajustes .am-espaco[data-e="arejado"] { letter-spacing: .06em; word-spacing: .18em; }

/* NÃO há filete de margem, e isso é decisão testada no iPad (03 §5.1), não
   esquecimento. A barra marca o PARÁGRAFO inteiro enquanto o destaque é de um
   TRECHO: o olho lê a barra como se o bloco todo estivesse marcado, e a
   discrepância incomoda em leitura longa. O <mark> já diz onde o destaque
   está; um segundo indicador com granularidade diferente subtrai informação.

   A classe `.tem-destaque` continua sendo posta no bloco — serve de âncora
   para o salto de volta da L-54 —, mas sem pintura. O §3.3 da spec ainda
   mostra o filete num trecho de CSS antigo; quem vale é o §5.1, que é
   posterior e registra o teste. */

/* ── A seleção nativa É o feedback do modo B ───────────────────────────────
   `user-select: none` NÃO entra aqui, e a regra tem dono: no protótipo ela
   existe presa ao **modo A** (`[data-gesto="tinta"]`), onde a tinta ao vivo
   competiria com a seleção do sistema. O modo B venceu a L-04b justamente
   porque a seleção mostra o alcance ENQUANTO se arrasta — desligá-la apaga o
   feedback inteiro: o traço passa a funcionar às cegas e só aparece depois de
   confirmado.

   `pan-y` preserva o scroll vertical do dedo e mata gesto horizontal; o
   `touch-callout` evita o menu do iOS disputando o toque longo. */
.prosa.modo-caneta { touch-action: pan-y; -webkit-touch-callout: none; }

/* E ela é pintada NA COR ATIVA, a 62%: o que se vê antes de confirmar é o
   resultado, não uma seleção azul de sistema que não diz nada sobre o que vai
   ficar na página. */
.prosa::selection, .prosa *::selection {
  background-color: color-mix(in srgb, var(--cor-ativa, var(--hl-roxo)) 62%, transparent);
  color: inherit;
}
[data-cor-ativa="roxo"]    { --cor-ativa: var(--hl-roxo);    --cor-ativa-viva: var(--vivo-roxo); }
[data-cor-ativa="amarelo"] { --cor-ativa: var(--hl-amarelo); --cor-ativa-viva: var(--vivo-amarelo); }
[data-cor-ativa="rosa"]    { --cor-ativa: var(--hl-rosa);    --cor-ativa-viva: var(--vivo-rosa); }
[data-cor-ativa="azul"]    { --cor-ativa: var(--hl-azul);    --cor-ativa-viva: var(--vivo-azul); }

/* O botão é o ÚNICO indicador de modo. Um contorno na área de texto foi
   testado no Bloco A e descartado: no iPad, onde o modo vive ligado, virava
   moldura permanente em volta do artigo. Estado da ferramenta se comunica na
   ferramenta, não na superfície de trabalho. */
/* Acima da barra inferior, e por isso o `--barra-h`: sobre ela, o botão
   cairia sobre um alvo de navegação — e o dedo que quer marcar acertaria
   "Destaques". */
/* Desde 02/09 a forma, a superfície e a posição vêm da CÁPSULA — aqui fica só
   o que é da caneta: o glifo e o estado ligado. A nota de cima («acima da
   barra inferior, para o dedo não acertar Destaques») continua valendo: quem
   a honra agora é a base da pilha, `--pilha-y`. */
#caneta { font-size: 1.25rem; }
/* O botão ligado veste a COR ATIVA — é onde o leitor lê em que cor vai marcar,
   sem abrir nada. Cor viva e texto escuro em qualquer tema: é cromo sobre
   cromo, não marcação sobre texto. */
/* O halo encolheu de 6px para 5px e perdeu a sombra composta: dentro de uma
   cápsula com `overflow: hidden` o anel de 6px era cortado pela borda, e uma
   sombra erguida dentro de uma peça que já tem a dela é sombra duplicada. */
#caneta[aria-pressed="true"] {
  background: var(--cor-ativa-viva, var(--vivo-roxo)); color: #201c14;
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--cor-ativa-viva, var(--vivo-roxo)) 34%, transparent);
}

/* ── A bolha de perguntar  (Bloco J8) ──────────────────────────────────────
   Primeiro degrau, colada na caneta, e a razão é uma regra de coluna que vale
   daqui para a frente: **embaixo o que age sobre o texto, em cima o que
   configura a tela.** Marcar e perguntar são o mesmo gesto de leitura — a
   reação ao parágrafo que se acabou de ler —, e são os dois que precisam do
   alcance curto do polegar. Ouvir, velocidade e `Aa` sobem um degrau por isso.

   O `?` em SERIFA, como o `Aa` do quarto degrau: num círculo de 56px o sinal
   deixa de ser ícone de sistema (onde `?` significa «ajuda») e vira marca
   tipográfica — e este app não tem ajuda nenhuma para o sinal disputar.

   NEUTRA como as irmãs, e não vestida do acento que o `.btn.ia` do rodapé usa:
   na coluna o acento já quer dizer «este painel está aberto» (ver a velocidade
   e o `Aa`), e um terceiro sentido para a mesma cor, permanente, apagaria os
   outros dois. Quem carrega a identidade da IA é o sheet que ela abre. */
#perguntar-flutuante {
  font-family: var(--serif); font-size: 1.35rem; font-weight: 500;
}
#perguntar-flutuante[hidden] { display: none; }

/* ── Controle flutuante de pausar/retomar a leitura falada (Bloco J) ───────
   O dono relatou o problema de ponta a ponta: o player mora no cabeçalho,
   pausar exige rolar até lá, rolar é gesto manual e desliga o acompanhamento
   automático — o próprio ato de alcançar o controle mata o que ele foi
   buscar. Isto é o conserto: um controle igual em espécie ao `#caneta`
   acima (mesmo tamanho, mesmo `position: fixed`, mesmo canto), sempre ao
   alcance do polegar sem precisar sair do lugar onde se está lendo.

   EMPILHADO acima do `#caneta`, não ao lado: os dois vivem juntos na tela de
   artigo, e uma coluna no mesmo canto não disputa o polegar do jeito que duas
   bolhas lado a lado disputariam — nem exige decidir uma segunda coordenada
   horizontal.

   ── Perene, desde o Bloco J6 ──────────────────────────────────────────────
   Este botão aparecia só DURANTE a escuta, e a janela era curta demais: quem
   volta a um artigo de 50 minutos cai no meio do texto, onde não havia play
   nenhum — o cabeçalho ficava a uma rolagem inteira, e a rolagem era o gesto
   que o botão de cima existe para não exigir. Agora ele acompanha o ARTIGO,
   como o `#caneta`, e o que muda com o estado da voz é o glifo (▶/⏸). Só o
   `#rolagem-flutuante` abaixo continua preso à sessão — fora dela não há
   rolagem que acompanhe voz nenhuma. */
/* A POSIÇÃO deixou de ser declarada item a item: quem ordena os três é a
   ordem no DOM, dentro da cápsula. É o que faz uma bolha que some não deixar
   buraco — antes, com degrau fixo, as de cima não desciam para ocupar o lugar
   dela. */
#ouvir-flutuante { font-size: 1.25rem; }

/* ── O relógio da espera  (06/09) ──────────────────────────────────────────
   «hoje eu clico e nada acontece, e demora muito a gerar.» O glifo do play dá
   lugar a `1:32` enquanto a Azure sintetiza, e volta ao `▶` quando a narração
   chega. A receita tipográfica é a da bolha da velocidade ao lado, e pelo
   mesmo motivo: cinco caracteres num círculo de 48px, com o pior caso
   (`12:03`) medido no harness em vez de estimado.

   `tabular-nums` não é capricho — o número repinta a cada segundo, e sem
   largura fixa de algarismo «1:19» e «1:11» ocupam larguras diferentes: o
   texto pularia de lado uma vez por segundo.

   NENHUMA animação, e isso é decisão. Pulsar a opacidade de um glifo parado
   (o que a bolinha da lista faz) diz «vivo»; pulsar um texto que se LÊ atrapalha
   a leitura dele. Aqui o sinal de vida é o próprio relógio andando.

   `--cromo-acento` porque a cápsula é campo grafite nos três temas: o acento
   do papel seria tinta escura sobre campo escuro. Mesma regra de 02/09 —
   clarear a tinta, nunca o campo. */
#ouvir-flutuante[data-estado="gerando"] {
  font-family: var(--sans); font-size: 11px; font-weight: 600;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
  color: var(--cromo-acento);
}

/* A síntese parou, e o botão que se tocou é quem conta. O motivo inteiro está
   no `aria-label` e no `title` — num círculo de 48px não cabe frase, e a frase
   continua também no aviso do cabeçalho, que tem a largura para ela. */
#ouvir-flutuante[data-estado="falhou"] {
  font-family: var(--sans); font-size: 1.1rem; font-weight: 700;
  color: var(--cromo-perigo);
}

/* ── A bolha da velocidade da narração  (Bloco J7) ─────────────────────────
   Terceiro degrau. Ela é a única bolha da coluna que carrega TEXTO em vez de
   glifo, e isso não é estilo: é o desenho. Um velocímetro desenhado diria
   «aqui se muda a velocidade» sem dizer QUAL — e a pergunta que se faz
   olhando para a tela é a segunda. O número é o estado; o deslizante que ela
   abre é a mudança.

   `tabular-nums` porque o valor troca sozinho enquanto o dedo arrasta o
   deslizante ao lado, e sem largura fixa de algarismo o texto dança dentro do
   círculo.

   `.72rem`, e ela é a MENOR letra da coluna — menor até que a do percentual ao
   lado, que também carrega texto. Não é inconsistência: é que o pior caso dela
   tem cinco caracteres (`1,25×`), e o do percentual tem três (`23%`). Medir a
   fonte pelo rótulo mais curto é como o texto estoura em silêncio.

   Foi exatamente o que aconteceu ao encolher a bolha de 56 para 48px em 01/09:
   `.86rem` desceu para `.8rem`, o `23%` ficou com 17px de folga e o `1,25×`
   ficou com **zero** — dentro do círculo, encostado nas duas bordas. O harness
   agora mede `clientWidth − scrollWidth` nas duas e exige 8px, para que a
   próxima mudança de diâmetro seja um teste vermelho e não uma descoberta no
   aparelho. */
#velocidade-flutuante {
  font-family: var(--sans); font-size: 11px; font-weight: 600;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}
#velocidade-flutuante[hidden] { display: none; }
/* Aberta, ela veste o acento: o painel ao lado é um objeto flutuante sobre a
   mesa, e sem a bolha acesa não há nada dizendo de onde ele saiu. */
/* Aberta, ela veste o acento. A borda saiu junto com a bolha: dentro da
   cápsula o item não tem contorno próprio, então quem diz «este está aberto» é
   a tinta e o leito. */
/* Sobre o campo grafite quem diz «aberto» é o `--cromo-acento` — o acento do
   tema escuro, em qualquer tema (02/09). O acento do papel, aqui, seria tinta
   escura sobre campo escuro. */
#velocidade-flutuante[aria-expanded="true"] {
  color: var(--cromo-acento);
  background: color-mix(in srgb, var(--cromo-acento) 13%, transparent);
}

/* ── O deslizante que ela abre ─────────────────────────────────────────────
   Ao LADO da bolha, e não por cima da coluna: o dedo que acabou de tocar o
   número continua sobre ele, e um painel que nascesse embaixo do dedo seria
   um painel que o próprio toque de abertura já estaria arrastando.

   Alinhado pela BASE da bolha, com `min-height` igual ao diâmetro dela: as
   duas peças formam uma fileira só, e centrar por `transform` exigiria saber
   a altura do painel, que depende do texto.

   A largura é o que sobra da tela depois da coluna, com teto de 20rem — o
   trilho precisa de curso útil, e num telefone de 375px o que sobra ainda dá
   uns 270px. Abaixo disso o `.velocidade` do painel de voz já quebra a
   fileira sozinho. */
#velocidade-painel {
  position: fixed; z-index: 47;
  /* Ancorado na CÁPSULA, e não mais numa bolha solta: à esquerda dela, e
     alinhado pela base do item de velocidade — que é o terceiro da pilha
     contando de baixo (`--y-velocidade`). As duas contas saem dos tokens da
     geometria, então mudar a altura de um item move o painel junto. */
  right: calc(var(--capsula-x) + var(--capsula-l) + .6rem);
  bottom: calc(var(--pilha-y) + var(--y-velocidade));
  width: min(20rem, calc(100vw - var(--capsula-x) * 2 - var(--capsula-l) - .6rem));
  min-height: var(--capsula-item);
  display: flex; align-items: center;
  padding: .5rem .8rem;
  background: var(--papel-elev); border: 1px solid var(--papel-borda);
  border-radius: var(--raio); box-shadow: var(--sombra-erguida);
  transition: opacity var(--dur) var(--curva), transform var(--dur) var(--curva);
}
/* `visibility`, e não só `opacity`: um painel transparente continua sendo uma
   parada de teclado e continua sendo lido pelo VoiceOver. E não `display:
   none`, que levaria a transição junto. */
#velocidade-painel[data-aberto="nao"] {
  opacity: 0; visibility: hidden; pointer-events: none; transform: translateX(.5rem);
}
/* O bloco lá dentro é o MESMO `.controles-voz` do cabeçalho — o que muda é só
   que aqui ele não vem depois de nada, então a folga de cima sai. */
#velocidade-painel .controles-voz { margin-top: 0; width: 100%; }

/* ── A bolha dos ajustes de leitura  (Bloco J7) ────────────────────────────
   Quarto degrau, e o mesmo `Aa` do cabeçalho — mesmo rótulo porque é o mesmo
   painel, e um segundo nome para a mesma porta é uma porta a mais na cabeça
   de quem usa.

   Em SERIFA, e o cabeçalho em sans: lá o `Aa` é uma pílula de cromo entre
   outras; aqui ele tem 56px e é a única coisa dentro do círculo. Nesse
   tamanho a letra deixa de ser rótulo e vira ESPÉCIME — mostra a tipografia
   de que o painel trata, que é o mesmo princípio das amostras lá dentro
   («o controle mostra o que ele faz»). */
/* Em SANS desde 02/09, e a nota acima explica por que ele era serifado: num
   círculo de 56px o `Aa` deixava de ser rótulo e virava espécime. Num item de
   52×48 dentro de uma cápsula ele volta a ser rótulo — e o espécime de
   verdade está dentro do painel que ele abre, onde a fonte se apresenta na
   própria fonte. */
#ajustes-flutuante {
  font-family: var(--sans); font-size: 15px; font-weight: 600;
}
#ajustes-flutuante[hidden] { display: none; }
#ajustes-flutuante[aria-expanded="true"] {
  color: var(--cromo-acento);
  background: color-mix(in srgb, var(--cromo-acento) 13%, transparent);
}

/* Fora do artigo não há o que ajustar nem o que narrar. O `data-rota` já
   existe no `<body>` (ver `#tempo-leitura` logo abaixo), e é ele quem recolhe
   as duas bolhas e o painel — sem isso, o `hidden = false` que a tela de
   leitura escreve nunca seria desfeito, e o `Aa` ficaria pendurado sobre a
   inbox abrindo um painel de tipografia para uma lista. */
body:not([data-leitura]) #velocidade-flutuante,
body:not([data-leitura]) #velocidade-painel,
body:not([data-leitura]) #perguntar-flutuante,
/* O `▶` e o `✎` entraram nesta lista em 03/09, e estavam de fora desde
   sempre: os dois são escondidos por `hidden` no JavaScript, e `hidden` é um
   estado que alguém tem de LEMBRAR de repor. Bastava sair de um artigo por um
   caminho que não passasse pelo lugar certo para eles ficarem pairando sobre a
   inbox e a escrivaninha — duas bolhas para narrar e marcar um texto que não
   está em cena.
   Mesma razão das irmãs acima: fora da leitura não há o que narrar nem o que
   marcar, e a rota já responde por isso sem ninguém precisar lembrar. */
body:not([data-leitura]) #ouvir-flutuante,
body:not([data-leitura]) #caneta,
body:not([data-leitura]) #compartilhar-flutuante,
body:not([data-leitura]) #ajustes-flutuante { display: none; }

/* ── O `⇧` tem uma pergunta A MAIS que as irmãs  (spec 25 §3.3) ────────────
   `#capsula-mao` vive nas DUAS rotas de leitura, e as irmãs valem nas duas.
   Este não: na escrivaninha, «compartilhar» é o estudo inteiro — visão geral,
   partes e síntese num arquivo só —, e uma etapa solta não é o gesto que se
   quer. A ação está no `⋯`, que é onde as ações do estudo moram.

   Duas regras porque são duas perguntas: `[data-leitura]` responde «há texto
   em cena?» e `[data-rota]` responde «esta rota mostra o botão?». Uma só não
   dá conta de nenhuma das duas. */
body[data-rota="estudo"] #compartilhar-flutuante { display: none; }

/* ── O interruptor da autorrolagem  (Bloco J4) ─────────────────────────────
   O TOPO da coluna desde o Bloco J7 (era o terceiro degrau, quando a coluna
   tinha três), e o relato que o pediu é a continuação exata
   do de cima: com o botão de pausa ao alcance, pausar deixou de exigir a
   subida ao cabeçalho — mas QUALQUER outro toque que role a página continua
   desligando o acompanhamento, e não havia como pedi-lo de volta sem parar a
   voz.

   Mesmo material dos irmãos (papel elevado, borda em regra, sombra erguida):
   é a mesma família de cromo flutuante, e um botão diferente em espécie
   sugeriria uma função de outra ordem.

   ── Por que o estado se vê sem depender de cor ────────────────────────────
   Este botão é também o MOSTRADOR: o desligar por gesto é silencioso — o
   texto simplesmente para de andar. O apagado, então, precisa se ler de
   relance e sem cor: além de descer a tinta para `--tenue`, o `::after`
   risca o ícone. Uma opacidade a menos é diferença que só existe lado a lado
   com a versão acesa, e ninguém vê as duas ao mesmo tempo. */
#rolagem-flutuante {
  /* ── O TOPO da coluna, e por que é aqui  (Bloco J7) ─────────────────────
     Ele é a única bolha que aparece e some DENTRO do artigo — nasce ao tocar
     e some no `ended`, enquanto as outras acompanham o artigo inteiro.
     Numa coluna posicionada por degrau fixo, uma bolha intermitente no meio
     abre um buraco: as de cima não descem para ocupar o lugar dela. No topo,
     o que ela deixa quando some é o vazio da mesa, que não se vê.
     (Subiu do 5 ao 6 quando o progresso entrou na coluna — a regra do topo
     é dela, não do número.) */
  font-size: 1.25rem;
}
/* A seta cresce ao ser riscada: o corte come o meio dela, e é o que sobra em
   cima e embaixo que ainda tem de se ler como seta — não como dois traços. */
/* Aceso é a tinta CHEIA do cromo, apagado é a tinta secundária mais o risco.
   Sobre grafite, `--tenue` (um cinza de papel) seria quase o próprio campo — e
   o mostrador que precisa se ler de relance é justamente este. */
#rolagem-flutuante[aria-pressed="true"] { color: var(--cromo-tinta); }
#rolagem-flutuante[aria-pressed="false"] { color: var(--cromo-tinta-2); font-size: 1.4rem; }
#rolagem-flutuante[aria-pressed="false"]::after {
  content: ""; position: absolute; left: 16%; right: 16%; top: 50%;
  height: 1.75px; border-radius: 2px; background: currentColor; transform: rotate(-45deg);
  /* A folga em volta do risco é o que o faz LER como risco: encostado no
     glifo os dois viram uma mancha só — foi o que o primeiro screenshot
     mostrou. O contorno acompanha a rotação porque mora no elemento girado. */
  box-shadow: 0 0 0 1.5px var(--cromo-2);
}
/* O `position: relative` que ancora este risco vem da regra genérica
   `.capsula > button` — antes vinha do `position: fixed` do próprio botão. */
#rolagem-flutuante[hidden] { display: none; }

/* ── A bolha do progresso de leitura  (02 §4, terceira encarnação) ─────────
   Era a barra de 4px no topo. Duas rodadas de conserto lá (2px quase
   subliminar → 4px em cor plena com marcos de meta) não resolveram a queixa
   original — "difícil de ver" —, e o diagnóstico da terceira é de POSIÇÃO,
   não de força: o topo da tela é onde o olho não está durante a leitura. A
   coluna da direita é onde ele já vai buscar os controles, então o progresso
   virou mais uma moradora dela: anel na borda + número no centro.

   Quinto degrau, ABAIXO da rolagem: a rolagem continua no topo porque a
   regra do topo é dela — é a única bolha intermitente, e um buraco no meio
   da coluna não se fecha sozinho (ver o comentário dela, acima).

   MOSTRADOR, não botão — mesmo argumento da pílula do tempo: `pointer-events:
   none` permanente elimina por construção a classe de bug do
   `data-ajustando`, porque o que não recebe toque não rouba a resposta do
   `caretRangeFromPoint` durante o arraste de alça. E mesmo z-index 44 dela,
   não o 46 das bolhas tocáveis: os dois números são famílias, e este aqui é
   da família dos que só se leem.

   O número segue o desenho da bolha de velocidade («o número é o estado»):
   sans .86rem 600, `tabular-nums` porque ele troca sozinho enquanto a página
   rola, e sem largura fixa de algarismo o texto dançaria dentro do círculo.

   SEMPRE visível na tela de artigo — não segue o `data-cromo`. É a correção
   inteira: um progresso que some enquanto se rola é um progresso que nunca
   está lá quando a leitura acontece. As bolhas irmãs já se comportam assim. */
/* Dentro da cápsula ele deixou de ser um círculo de 48px e virou um ANEL de
   30px centrado num item de 52 — a bolha inteira era a mancha mais pesada da
   coluna, e o que informa é o arco, não o disco em volta dele.
   `pointer-events: none` continua permanente aqui; a exceção do sumário está
   logo abaixo. */
#progresso-flutuante {
  /* O único item quadrado da pilha: o anel precisa de folga igual em volta, e
     52×48 daria um oval de 2px. */
  height: var(--capsula-anel);
  /* ── O arco é MONOCROMÁTICO dentro da cápsula  (04/09) ──────────────────
     `--progresso` é um azul de tinta (`#26436e` no claro), escolhido para ser
     lido sobre papel; sobre o campo grafite ele desaparece. O arco passa a
     usar a tinta do cromo, e com isso a coluna inteira volta a ser de uma cor
     só — a mesma razão pela qual os glifos das irmãs não são coloridos. A
     trilha e os marcos continuam derivados dele, então nada aqui precisou de
     um segundo valor. */
  --progresso: var(--cromo-tinta);
  pointer-events: none;
  font-family: var(--sans); font-size: 8.5px; font-weight: 600;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
  /* O ponto de partida do anel. Quem escreve o valor real é `ligarRolagem`,
     a cada quadro de rolagem — o mesmo lugar que escrevia o width da barra. */
  --p: 0;
}
/* O número mora no furo do anel, e o furo tem 22px: um `<span>` sem caixa
   própria seria centrado pelo item de 52 e sairia do buraco assim que o anel
   deixasse de ser concêntrico. */
/* O disco por trás do número era `--papel-elev`: dentro da cápsula grafite ele
   virava uma pastilha clara no meio do anel. Some — quem já fura o centro é a
   máscara radial do `::before`, e o `z-index: 1` continua pondo o número na
   frente do arco. */
#progresso-flutuante > span {
  position: relative; z-index: 1;
  width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  background: transparent;
}

/* ── Quando o texto TEM estrutura, a bolha aceita o toque  (L-124) ──────────
   O `pointer-events: none` acima é permanente de propósito, e o comentário
   original explica por quê: o que não recebe toque não rouba a resposta do
   `caretRangeFromPoint` durante o arraste de alça. Isso continua valendo — a
   exceção é estreita e declarada em duas frentes.

   Primeira: só em artigo com sumário. Na notícia curta, que é a maioria do
   acervo, nada muda em nenhum aspecto — nem o hit-test, nem o z-index.

   Segunda: durante o ajuste de alça ela volta a ser intocável, agora pela
   lista do `body[data-ajustando]` lá em cima, onde ela entrou junto com esta
   regra. É o mesmo tratamento das seis bolhas irmãs; o que a mantinha fora da
   lista era ser mostrador, e ela deixou de ser só isso.

   O z-index sobe de 44 para 46 no mesmo movimento: os dois números são
   famílias — 44 é dos que só se leem, 46 dos que se tocam — e a bolha muda de
   família exatamente quando muda de natureza. */
#progresso-flutuante[data-sumario="sim"] { pointer-events: auto; z-index: 46; cursor: pointer; }

/* O anel: um conic-gradient dirigido por `--p`, furado no centro pela
   máscara radial — sem ela o arco seria um disco cheio por trás do número.
   Preenche em sentido horário a partir do topo, que é onde a leitura começa.

   Os MARCOS de meta (25·50·75%) vêm na segunda camada, POR BAIXO do arco:
   meta vencida é absorvida pela cor plena, não celebrada com efeito — a
   mesma semântica dos traços da barra antiga, na mesma força (55%, a que a
   página de amostras validou). Cada tick tem 4,5° (~2px de arco no raio de
   26px): os 2,5° da primeira tentativa davam ~1px, o mesmo erro do marco de
   1px da barra — marco que não se vê não é meta, é ruído de render.

   `inset: 2px` deixa 1px de papel entre a borda da bolha e o anel — colado
   na borda, o arco e o contorno viravam um traço só. A espessura de 4px é
   a da barra que ele substitui. */
#progresso-flutuante::before {
  content: ""; position: absolute; border-radius: 50%;
  /* 30px centrados, e não `inset` na caixa toda: a caixa agora é o item da
     cápsula (52×52), e o anel é uma peça dentro dele. */
  width: 30px; height: 30px; top: 50%; left: 50%; margin: -15px 0 0 -15px;
  --marco: color-mix(in srgb, var(--progresso) 55%, transparent);
  /* ── A TRILHA, terceira camada e a de baixo  (31/08) ────────────────────
     Sem ela, um artigo em 0% desenha três risquinhos soltos na borda — os
     marcos de 25, 50 e 75% sobre nada — e o que se vê não parece um anel
     vazio, parece sujeira na tela. Foi assim que o dono a descreveu, e ele
     tinha razão: marco é referência DENTRO de um percurso, e sem o percurso
     desenhado ele não referencia coisa nenhuma.

     Derivada de `--progresso`, e não um cinza próprio: assim ela acompanha o
     acento em qualquer tema, e o anel inteiro continua sendo uma cor só em
     duas intensidades. */
  --trilha: color-mix(in srgb, var(--progresso) 14%, transparent);
  background:
    conic-gradient(var(--progresso) calc(var(--p) * 1%), transparent 0),
    conic-gradient(transparent 0 87.75deg,  var(--marco) 0 92.25deg,
                   transparent 0 177.75deg, var(--marco) 0 182.25deg,
                   transparent 0 267.75deg, var(--marco) 0 272.25deg,
                   transparent 0),
    linear-gradient(var(--trilha), var(--trilha));
  /* O furo de 22px num anel de 30 dá 4px de arco, que é a espessura da barra
     que ele substituiu — a mesma conta de antes, refeita para o raio novo. */
  -webkit-mask: radial-gradient(closest-side, transparent 11px, #000 12px);
  mask: radial-gradient(closest-side, transparent 11px, #000 12px);
}

/* Fora do artigo não há meta de leitura — era a regra da #barra-marcos e
   continua sendo a desta bolha. Por `data-rota`, e não por `hidden`: nenhuma
   tela a revela, então nenhuma teria de recolhê-la. */
body:not([data-leitura]) #progresso-flutuante { display: none; }

/* ── A pílula do tempo de leitura  (spec 14 §4.2) ──────────────────────────
   Pílula, e não bolha: são dois números, e "25 min · 1h10" não cabe num
   círculo de 56px. Mesmo material da caneta acima — papel elevado, borda em
   regra, sombra erguida — porque é a mesma família de cromo flutuante; o que
   muda é que este não se toca.

   `pointer-events: none` PERMANENTE, e isso elimina uma classe inteira de bug
   por construção: a pílula nunca precisa entrar na lista do
   `body[data-ajustando]` lá em cima, que desliga o hit-test da caneta, das
   ações e da barra durante o arraste de alça. Arrastar uma alça pergunta ao
   documento que texto está sob o dedo, e qualquer elemento por cima da prosa
   responde por si — o que não recebe toque não tem como roubar a resposta. */
#tempo-leitura {
  position: fixed; right: 1.1rem; bottom: var(--pilha-base);
  z-index: 44; pointer-events: none;
  display: flex; align-items: center; gap: .3rem;
  height: var(--tempo-h); padding: 0 .6rem;
  border-radius: 999px;
  background: var(--papel-elev); border: 1px solid var(--regra);
  box-shadow: var(--sombra-erguida);
  font-family: var(--sans); font-size: .68rem; line-height: 1;
  color: var(--tinta); white-space: nowrap;
  /* Só a opacidade e o deslocamento, nunca `display`: a transição existe para
     que o número acompanhe o cromo em vez de aparecer estalando, e `display`
     não transiciona. */
  transition: opacity .18s ease, transform .18s ease;
}
#tempo-leitura[hidden] { display: none; }

/* O acumulado é secundário POR DESENHO: a sessão é o que está acontecendo, o
   total é o que já aconteceu. */
#tempo-leitura .sep { color: var(--tenue); }
#tempo-leitura .rot {
  font-size: .6rem; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--tenue);
}

/* Segue o cromo. É esta regra que responde à proibição da 02 §4 ("sem contador
   de palavras piscando"): enquanto se lê rolando para baixo o número não está
   lá — ele volta com a barra, quando o leitor levanta os olhos. */
body[data-cromo="oculto"] #tempo-leitura { opacity: 0; transform: translateY(.4rem); }

/* Fora do artigo não há sessão de leitura para contar. O `data-rota` já existe
   no `<body>` exatamente para uma regra saber isto sem que nenhuma tela avise. */
body:not([data-leitura]) #tempo-leitura { display: none; }

/* ── barra de ações do destaque (L-51, 03 §5.2) ────────────────────────────
   Pílula flutuante, posicionada em coordenadas de DOCUMENTO (`absolute`) e não
   de viewport: em `fixed` ela ficaria parada enquanto o texto rola por baixo, e
   apontaria para o trecho errado no primeiro movimento do dedo. */
#acoes {
  position: absolute; z-index: 60; display: flex; align-items: stretch; gap: 0;
  /* ── Ícone sobre legenda  (19/09) ──────────────────────────────────────────
     A pílula de rótulos corridos, com o aro de acento no ajuste e a dica
     «arraste as alças…», saiu a pedido: «lúdico, de estética de mau gosto».
     Das três propostas da página de amostras, a escolhida foi esta — cada ação
     é um desenho com a legenda curta embaixo, num cartão de filete quase
     invisível e sombra erguida. É também a única das três que cabe numa linha
     no iPhone 16 Pro Max (pede 416 px dos 424). */
  background: var(--papel-elev); border: 1px solid var(--papel-borda-fina); border-radius: 16px;
  box-shadow: var(--sombra-erguida); padding: 4px;
  font-family: var(--sans); white-space: nowrap;
  /* ── Nunca mais larga que a tela: QUEBRA em linhas  (17/09) ──────────────
     A captura do dono no iPhone 16 Pro Max: a pílula do ajuste tem nove itens
     desde a L-73, mede 791 px numa tela de 440, e da «Nota» em diante nada se
     alcançava — `posicaoDaBarra` prende a borda ESQUERDA, e a direita saía.
     `white-space: nowrap` continua nos botões (uma legenda não parte ao meio);
     quem quebra é a fileira. `acoes.mjs` marca `data-quebrada` quando isso
     acontece — num iPhone de 390 px, ou com as quatro cores abertas. */
  max-width: calc(100vw - 16px); box-sizing: border-box;
  flex-wrap: wrap; justify-content: center; row-gap: 2px;
}
#acoes[hidden] { display: none; }
/* Em duas linhas o fio entre grupos fica solto no começo ou no fim de uma
   linha, e some; o raio fica o mesmo (a pílula de 999px é que virava estádio). */
#acoes[data-quebrada] { border-radius: 16px; }
#acoes[data-quebrada] .sep { display: none; }

/* 48px de alvo: a caneta e o dedo precisam do alvo grande. O desenho em cima,
   a legenda de 11px embaixo; a cor de repouso é a da tinta secundária, e o
   realce é o papel um degrau abaixo, não uma cor. */
#acoes button { display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 5px; border: 0; background: none; color: var(--tinta-2); cursor: pointer;
  font: 500 .6875rem/1 var(--sans); letter-spacing: .005em;
  min-width: 48px; min-height: 48px; padding: 8px 4px 7px; border-radius: 11px; }
#acoes button .ic { display: grid; place-items: center; width: 24px; height: 20px; pointer-events: none; }
#acoes button .ic svg { width: 20px; height: 20px; pointer-events: none; }
#acoes button .leg { pointer-events: none; }
#acoes button:hover, #acoes button:focus-visible { background: var(--papel-elev-2); color: var(--tinta); }
#acoes button:active { background: var(--regra); }
/* O que confirma é o único com massa: o visto (ou o marcador) num disco de
   acento, e a legenda no acento. */
#acoes .primaria, #acoes .primaria:hover { color: var(--acento); }
#acoes .primaria .ic { width: 24px; height: 24px; margin: -2px 0; border-radius: 50%;
  background: var(--acento); color: var(--sobre-acento); }
#acoes .primaria .ic svg { width: 15px; height: 15px; }
#acoes .perigo, #acoes .perigo:hover { color: var(--perigo); }
/* Fechar é só o desenho, menor e mais apagado: ele sai do caminho. */
#acoes .so-icone { min-width: 36px; color: var(--tenue); }
#acoes .so-icone .ic svg { width: 16px; height: 16px; }
#acoes .so-icone .leg { display: none; }
/* O rótulo de "já fiz": copiar não muda nada na tela, e sem um sinal o leitor
   toca de novo para ter certeza. O desenho vira um visto por ~1,4s. */
#acoes .feita  { color: var(--acento); }
#acoes .falhou { color: var(--perigo); }
#acoes .sep { width: 1px; background: var(--regra); margin: 10px 4px; flex: none; }
/* Abaixo de 430px (o iPhone de 390, o SE) os oito botões pediam 416 px e o ✕
   caía sozinho numa segunda linha. Um passo mais justo — o alvo continua com
   44px de altura e de largura mínima — e a fileira volta a caber em uma. */
@media (max-width: 430px) {
  #acoes { padding: 3px; }
  #acoes button { min-width: 44px; padding: 8px 2px 7px; font-size: .65rem; letter-spacing: 0; }
  #acoes .so-icone { min-width: 32px; }
  #acoes .sep { margin: 10px 2px; }
}

/* A amostra de cor ocupa o lugar do desenho: uma pinta de 20px. */
#acoes .pinta { display: block; width: 20px; height: 20px; border-radius: 50%;
  background: var(--hl-cor); box-shadow: inset 0 0 0 1px rgba(0,0,0,.12); }
/* Aberto o seletor, a cor em uso ganha o anel; recolhido, o botão é um menu
   (`aria-expanded`) e a legenda «Cor» já diz isso. */
#acoes .swatch[aria-pressed="true"]:not([aria-expanded]) .pinta {
  box-shadow: 0 0 0 2px var(--papel-elev), 0 0 0 3px var(--tinta); }
/* O seletor de cor recolhido (L-73, spec 13 §2.2).
   `display: contents` faz o <span> desaparecer da caixa e as amostras
   participarem do flex da própria barra — sem isso, expandido viraria uma
   caixa dentro da caixa e a pílula ganharia um degrau de altura. */
#acoes .cores { display: contents; }
#acoes .swatch[data-cor="roxo"]    { --hl-cor: var(--vivo-roxo); }
#acoes .swatch[data-cor="amarelo"] { --hl-cor: var(--vivo-amarelo); }
#acoes .swatch[data-cor="rosa"]    { --hl-cor: var(--vivo-rosa); }
#acoes .swatch[data-cor="azul"]    { --hl-cor: var(--vivo-azul); }

/* ── modo ajuste (03 §5.2b, refeito na spec 45) ────────────────────────────
   O original vira FANTASMA enquanto se ajusta. Sem isso, ao encolher, a parte
   removida continuaria pintada e o gesto pareceria não ter efeito — o mesmo
   padrão de defeito da absorção, em outra roupa.

   Era classe numa `<mark>` (`.editando`) e é um NOME de highlight próprio: o
   `pigmento.ajuste()` pinta a proposta enquanto ela é puxada. Trocar a cor no
   meio do ajuste não o apaga mais — o `ajuste.remarcar()`, que existia só para
   repor a classe que a repintura destruía, morreu com a spec 45.

   O `outline` tracejado virou `underline dashed`: `::highlight()` não aceita
   contorno, e a mensagem — «isto é proposta, não fato» — é a mesma. As alças
   nas duas pontas continuam dizendo o resto.

   `--cor-ajuste` vem do `[data-cor-ajuste]` no documento, publicado por
   `pigmento.ajuste(segmentos, cor)`: é a cor DO DESTAQUE em edição, que pode
   não ser a cor ativa da barra. */
[data-cor-ajuste="amarelo"] { --cor-ajuste: var(--hl-amarelo); }
[data-cor-ajuste="roxo"]    { --cor-ajuste: var(--hl-roxo); }
[data-cor-ajuste="rosa"]    { --cor-ajuste: var(--hl-rosa); }
[data-cor-ajuste="azul"]    { --cor-ajuste: var(--hl-azul); }
::highlight(destaque-ajuste) {
  background-color: color-mix(in srgb, var(--cor-ajuste, var(--hl-amarelo)) var(--hl-fantasma, 22%), transparent);
  text-decoration: underline dashed var(--acento);
  text-decoration-thickness: 1px;
  text-underline-offset: .16em;
}

/* A bolinha de nota saiu na spec 45 — sem elemento não há `::after`. O sinal
   agora é o `underline dotted` de `::highlight(destaque-*-nota)`, lá em cima,
   onde a troca está explicada. */

/* Alças próprias: o iOS não desenha alças arrastáveis em seleção criada por
   programa em conteúdo não editável (medido no Bloco A). `touch-action: none`
   é o que impede a página de rolar enquanto se puxa. */
.alca { position: absolute; z-index: 58; width: 44px; margin-left: -22px; display: none;
  touch-action: none; -webkit-user-select: none; user-select: none; cursor: ew-resize; }
.alca.on { display: block; }
.alca > i { position: absolute; left: 50%; top: 0; width: 2px; height: 100%; margin-left: -1px;
  background: var(--acento); display: block; }
/* pousada: a bolinha de arraste toca a linha de texto — apoiada, não
   flutuando acima dela como a pílula de ações. */
.alca > i::after { content: ""; position: absolute; left: 50%; width: 18px; height: 18px;
  margin-left: -9px; border-radius: 50%; background: var(--acento); box-shadow: var(--sombra-pousada); }
#alcaA > i::after { top: -18px; }
#alcaB > i::after { bottom: -18px; }
.alca.puxando > i::after { transform: scale(1.25); }

/* ── sheet da nota (03 §5.3) ───────────────────────────────────────────────
   Mesma família do painel de ajustes: o leitor já aprendeu que o que vem de
   baixo se fecha para baixo. Nunca há botão "salvar" — ver nota.mjs. */
/* ── Painel flutuante, e não mais sheet de rodapé  (L-76) ──────────────────
   Ancorado na base, ele ficava **atrás do teclado**: no iPad o teclado ocupa
   quase metade da tela, e escrever sem ver o que se escreve não é escrever.
   Flutuando no terço superior, o painel permanece visível com qualquer
   teclado — encaixado ou flutuante.

   Fica claro o que isto NÃO resolve: o tamanho do teclado é ajuste do
   sistema, e nenhuma página escolhe. O que se resolve é o painel deixar de
   disputar o mesmo pedaço de vidro com ele. */
#nota, #conversa, #colar, #metadados, .sheet {
  position: fixed; z-index: 70;
  top: max(4.5rem, env(safe-area-inset-top)); left: 50%;
  width: min(36rem, calc(100% - 2rem));
  /* ── Quem rola é a LISTA, não o painel  (L-81) ───────────────────────────
     Com `overflow-y` no painel inteiro, uma conversa longa empurrava a linha
     dos botões para fora da área visível — «Perguntar» e «Fechar» existiam
     abaixo do corte, e enviar só funcionava pelo Enter. Controle que sai da
     tela é controle que não existe.

     Coluna flexível: a lista de turnos encolhe e rola por dentro, o campo e
     os botões ficam presos no pé do painel, sempre alcançáveis. */
  max-height: min(70vh, 34rem);
  display: flex; flex-direction: column; min-height: 0;
  background: var(--papel-elev); border: 1px solid var(--regra); border-radius: 14px;
  /* Sombra de objeto que paira, e não a aresta do rodapé: ele deixou de estar
     ancorado numa borda, então a luz volta a vir de --luz-x. */
  box-shadow: var(--sombra-flutuante, 0 12px 40px rgba(0,0,0,.35));
  padding: 1rem;
  font-family: var(--sans);
  transform: translate(-50%, -8px); opacity: 0; pointer-events: none;
  transition: opacity .16s ease, transform .16s ease;
}
/* ── ABRIR NÃO INTERPOLA `opacity`, E ISSO É O QUE DÁ TECLADO  (L-91) ──────
   O estado fechado é `opacity: 0`, e a transição de .16s COMEÇA nesse zero.
   Como `abrir()` foca no mesmo task em que marca `data-aberto="sim"` — e tem
   de focar ali, senão o iPadOS não liga o foco ao gesto —, o `focus()`
   acontecia com o painel medindo `opacity: 0`. Medido em Chrome headless:

       opacity no instante do campo.focus() = 0

   O WebKit não apresenta o teclado para um elemento que não considera
   visível. O campo ficava focado, o cursor piscava, e o teclado não vinha —
   o sintoma que custou seis rodadas de depuração em 21/08 e foi atribuído ao
   sistema (armadilha 52), porque o CSS parecia eliminado "por construção".

   `transition: none` aqui faz a abertura resolver `opacity: 1` de imediato;
   o deslize continua, agora como animação, que não mexe em `opacity`. O
   fade de FECHAMENTO não se perde: ele vem da regra base, que é o destino
   quando `data-aberto` volta a "nao".

   Regra que fica: painel que ganha foco não pode desvanecer a partir do
   zero. Ou abre opaco, ou anima a partir de um valor visível — é o que a
   gaveta do Tabula faz (`from{opacity:.4}`) e por isso ela nunca falhou. */
#nota[data-aberto="sim"], #conversa[data-aberto="sim"], #colar[data-aberto="sim"],
#metadados[data-aberto="sim"], .sheet[data-aberto="sim"] {
  transform: translate(-50%, 0); opacity: 1; pointer-events: auto;
  transition: none;
  animation: sheet-entra .16s var(--curva);
}
@keyframes sheet-entra { from { transform: translate(-50%, -8px); } }
#caixa-leitura-nota .pergunta, #caixa-destaques-nota .pergunta, #caixa-leitura-nota .trecho, #caixa-destaques-nota .trecho, #caixa-leitura-nota textarea, #caixa-destaques-nota textarea, #caixa-leitura-nota .linha, #caixa-destaques-nota .linha, #nota .pergunta, #nota .trecho, #nota textarea, #nota .linha {
  max-width: var(--measure); margin-inline: auto; }
/* A pergunta do turno de IA, acima do trecho (L-80). Em negrito porque é ela
   que dá sentido à resposta logo abaixo. */
#caixa-leitura-nota .pergunta, #caixa-destaques-nota .pergunta, #nota .pergunta { font-family: var(--sans); font-size: .92rem; font-weight: 600;
  color: var(--tinta); margin: 0 0 .5rem; }
#caixa-leitura-nota .trecho, #caixa-destaques-nota .trecho, #nota .trecho { font-family: var(--corpo); font-size: .9rem; color: var(--tinta-2);
  border-left: 2px solid var(--regra); padding-left: .7rem; margin-bottom: .7rem;
  max-height: 4.5em; overflow: hidden; }
/* 1rem, e não .92rem: abaixo de 16px o iOS DÁ ZOOM ao focar o campo — a
   página salta e o campo vai parar atrás do teclado. Vale para os dois
   textarea deste arquivo, e é o único lugar do app onde o número tem de ser
   lido em pixels de iPad, não em escala tipográfica. */
#caixa-leitura-nota textarea, #caixa-destaques-nota textarea, #nota textarea { display: block; width: 100%; min-height: 7rem; resize: vertical;
  font-family: var(--sans); font-size: 1rem; line-height: 1.5; color: var(--tinta);
  background: var(--papel); border: 1px solid var(--regra); border-radius: 8px; padding: .6rem .7rem; }
#caixa-leitura-nota textarea:focus-visible, #caixa-destaques-nota textarea:focus-visible, #nota textarea:focus-visible { outline: none; border-color: var(--acento); }
#caixa-leitura-nota .linha, #caixa-destaques-nota .linha, #nota .linha { display: flex; align-items: center; justify-content: space-between; margin-top: .7rem; }

/* ── A janela de METADADOS  (02/09) ────────────────────────────────────────
   «Preciso de alguma forma de editar metadados… pode ser por exemplo o símbolo
   de um lápis abre uma janela flutuante.»

   Nada de desenho novo: ela entra na família do `#nota`, do `#conversa` e do
   `#colar` — mesma caixa, mesma sombra, mesma entrada de .16s, mesmo lugar na
   tela. Uma quarta gramática de painel seria justamente o contrário do que o
   pedido manda («mantém a identidade visual»), e o app já tem três painéis que
   se abrem do mesmo jeito.

   O que ela acrescenta é só o formulário: dois campos rotulados, e a linha de
   botões que o `.linha` do `#nota` já desenha. */
#metadados { max-height: min(70vh, 26rem); gap: .1rem; }
#metadados .titulo-sheet {
  font-family: var(--sans); font-size: .78rem; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--tenue);
  margin: 0 0 .9rem;
}
/* O rótulo por CIMA do campo, e não ao lado: são dois campos de larguras
   diferentes, e rótulo à esquerda obrigaria a uma coluna fixa que o «Título»
   e o «Autor» não preenchem igual. */
.campo-meta { display: block; margin-bottom: .8rem; }
.campo-meta > span {
  display: block; font-family: var(--sans); font-size: .74rem; font-weight: 500;
  color: var(--tenue); margin-bottom: .3rem;
}
.campo-meta input {
  display: block; width: 100%; box-sizing: border-box;
  font-family: var(--serif); font-size: 1rem; color: var(--tinta);
  background: var(--papel); border: 1px solid var(--borda-controle);
  border-radius: var(--raio-p); padding: .6rem .7rem; min-height: var(--alvo);
  -webkit-appearance: none; appearance: none;
}
/* Serifa no valor e sans no rótulo: o que se digita aqui é o TÍTULO da obra, e
   ele vai aparecer em Literata na lombada, na capa e no alto da folha. Ver o
   texto na fonte em que ele vai viver é o mesmo princípio do espécime do
   painel de ajustes — «o controle mostra o que ele faz». */
.campo-meta input:focus-visible { outline: none; border-color: var(--acento); }
#metadados .linha {
  display: flex; align-items: center; gap: .5rem; margin-top: .2rem;
}
/* O estado (erro ou aviso) come a sobra e empurra os botões para a direita. */
#metadados .linha .sub { flex: 1; min-width: 0; color: var(--perigo); }
/* Salvar é PRIMÁRIO — é a ação que a janela existe para fazer. Mesmo desenho
   do «Publicar» do sheet de colar, que a revisão de 24/08 fixou. */
#metadados .btn.primario {
  background: var(--acento); color: var(--sobre-acento); border-color: var(--acento);
}

/* ── sheet da conversa (L-72, spec 12 §6.3) ────────────────────────────────
   Mesma família do sheet de nota: vem de baixo, fecha para baixo, mesma
   aresta. A diferença de forma segue a de conteúdo — a nota é um campo, a
   conversa é um histórico com um campo no pé. Por isso a lista rola dentro
   do sheet, e não o sheet dentro da tela: o campo de perguntar tem de ficar
   alcançável com o polegar por mais longa que a conversa fique. */
#caixa-leitura-perguntar .trecho, #caixa-leitura-perguntar .turnos, #caixa-leitura-perguntar textarea, #caixa-leitura-perguntar .linha, #conversa .trecho, #conversa .turnos, #conversa textarea, #conversa .linha, .sala .trecho, .sala .turnos, .sala textarea, .sala .linha {
  max-width: var(--measure); margin-inline: auto; }
#caixa-leitura-perguntar .trecho, #conversa .trecho, .sala .trecho { font-family: var(--corpo); font-size: .9rem; color: var(--tinta-2);
  border-left: 2px solid var(--acento); padding-left: .7rem; margin-bottom: .7rem;
  max-height: 3em; overflow: hidden; }
#caixa-leitura-perguntar .turnos, #conversa .turnos, .sala .turnos { flex: 1 1 auto; min-height: 0; overflow-y: auto; margin-bottom: .7rem; }
#caixa-leitura-perguntar .turnos .vazio, #conversa .turnos .vazio, .sala .turnos .vazio { color: var(--tinta-2); font-size: .9rem; text-align: center;
  padding: 1.2rem 0; }
#caixa-leitura-perguntar .turno, #conversa .turno, .sala .turno { margin-bottom: .9rem; position: relative; padding-right: 2.6rem; }
#caixa-leitura-perguntar .turno .p, #conversa .turno .p, .sala .turno .p { font-weight: 600; color: var(--tinta); font-size: .92rem;
  margin: 0 0 .25rem; }
/* O ✕ do turno é o irmão do `.destaque .x` — e a única porta de saída do
   turno de IA, que não é pintado no texto (L-88) e nunca abre a barra de
   ajuste. Armado, o botão diz "apagar?" por extenso: um ✕ que só muda de cor
   não avisa que falta o segundo toque. */
#caixa-leitura-perguntar .turno .x, #conversa .turno .x, .sala .turno .x {
  position: absolute; top: 0; right: 0; min-width: 32px; height: 32px;
  border: 0; background: none; color: var(--tinta-2); cursor: pointer;
  border-radius: 16px; font-size: .8rem; line-height: 1; opacity: .55;
  min-height: 32px; padding: 0 .5rem; font-family: var(--sans);
}
#caixa-leitura-perguntar .turno .x:hover, #caixa-leitura-perguntar .turno .x:focus-visible, #conversa .turno .x:hover, #conversa .turno .x:focus-visible, .sala .turno .x:hover, .sala .turno .x:focus-visible {
  opacity: 1; color: var(--perigo); background: var(--regra); }
#caixa-leitura-perguntar .turno .x.confirma, #conversa .turno .x.confirma, .sala .turno .x.confirma { opacity: 1; color: var(--perigo); background: var(--regra); }
/* A resposta é da máquina, e o filete à esquerda diz isso sem escrever
   "IA" em lugar nenhum — é o mesmo recurso que a citação do trecho usa. */
#caixa-leitura-perguntar .turno .r, #conversa .turno .r, .sala .turno .r { color: var(--tinta-2); font-size: .92rem; line-height: 1.55;
  margin: 0; border-left: 2px solid var(--regra); padding-left: .7rem;
  white-space: pre-wrap; }
/* 1rem pelo mesmo motivo do campo da nota — ver ali. */
#caixa-leitura-perguntar textarea, #conversa textarea, .sala textarea { flex: none; display: block; width: 100%; min-height: 3.2rem; resize: vertical;
  font-family: var(--sans); font-size: 1rem; line-height: 1.5; color: var(--tinta);
  background: var(--papel); border: 1px solid var(--regra); border-radius: 8px;
  padding: .6rem .7rem; box-sizing: border-box; }
#caixa-leitura-perguntar textarea:focus-visible, #conversa textarea:focus-visible, .sala textarea:focus-visible { outline: none; border-color: var(--acento); }
#caixa-leitura-perguntar .linha, #conversa .linha, .sala .linha { flex: none; display: flex; align-items: center; gap: .5rem; margin-top: .7rem; }
#caixa-leitura-perguntar .linha .sub, #conversa .linha .sub, .sala .linha .sub { flex: 1; }
#caixa-leitura-perguntar #conversa-enviar[disabled], #conversa #conversa-enviar[disabled], .sala #sala-enviar[disabled] { opacity: .55; }

/* ── sheet de colar um link (L-104, spec 16 §6) ────────────────────────────
   Terceiro membro da família do `#nota`/`#conversa`, e por isso já herdou a
   caixa flutuante e — o que importa de verdade — o `transition: none` da
   regra de abertura: sem ele o painel vale `opacity: 0` no instante do
   `focus()` e o iPadOS não apresenta o teclado (L-91).

   O que muda é só a forma: uma linha de texto, não um bloco. Um endereço não
   tem segunda linha, então `<input type="url">` — que no iPad ainda traz o
   teclado de endereço, com a tecla «.com». */
#colar .titulo, #colar input, #colar .linha {
  max-width: var(--measure); margin-inline: auto; }
/* Serif, não sans (revisão 2026-08-24): é o único título que este painel
   tem, e a voz de título do app é a Literata — a mesma do h1 da inbox e do
   artigo. Em sans ele lia como rótulo de formulário. */
#colar .titulo { font-family: var(--serif); font-size: 1.08rem; font-weight: 600;
  letter-spacing: -.01em; color: var(--tinta); margin: 0 0 .8rem; }
/* 1rem pelo mesmo motivo dos dois campos acima: abaixo de 16px o iOS DÁ ZOOM
   ao focar, a página salta e o campo vai parar atrás do teclado. */
/* Borda em --borda-controle, não --regra (revisão 2026-08-24 — mesmo caso da
   `.busca` dos destaques): o campo é a afordância principal do painel, e
   `--regra` sobre o papel do sheet era um aro que quase não existia. */
#colar input { display: block; width: 100%;
  font-family: var(--sans); font-size: 1rem; line-height: 1.5; color: var(--tinta);
  background: var(--papel); border: 1px solid var(--borda-controle);
  border-radius: var(--raio-p); padding: .65rem .8rem; box-sizing: border-box; }
#colar input:focus-visible { outline: none; border-color: var(--acento); }
#colar input::placeholder { color: var(--tenue); }

/* ── O arquivo escolhido e a pergunta sobre ele  (21/09/2026) ───────────────
   O painel de envio (EPUB, spec 50; arquivo, spec 68) nasceu SEM estilo para
   este bloco: o nome do arquivo e a pergunta de múltipla escolha herdavam o
   corpo de leitura (18–21px), e a regra `#colar input` acima — feita para o
   campo de link — pegava os rádios e os esticava numa linha inteira, com borda
   e enchimento de campo de texto. No EPUB mal se via («Literário», «Técnico»
   cabem em qualquer lugar); com «Documento — artigo, norma, manual, relatório»
   o painel virou o que o dono fotografou: enorme, quebrando linha.

   A voz é a do painel: sans, no tamanho dos botões. O nome do arquivo é a única
   coisa com peso; o resto é apoio. */
/* Sem `max-width`/centralização: a medida é em `em`, e com a fonte deste bloco ela
   ficava mais estreita que o painel — o nome do arquivo saía recuado do título. */
#colar-epub { font-family: var(--sans); }
#colar-epub-nome { margin: 0 0 .2rem; font-size: .95rem; font-weight: 600; line-height: 1.35;
  color: var(--tinta); overflow-wrap: anywhere; }
#colar-epub-meta { margin: 0 0 .8rem; }
#colar fieldset.temperamento { margin: 0 0 .9rem; padding: 0; border: 0; min-width: 0; }
#colar fieldset.temperamento[hidden] { display: none; }
#colar fieldset.temperamento legend { padding: 0; margin: 0 0 .25rem; font-size: .8rem; font-weight: 600;
  letter-spacing: .02em; color: var(--tinta-2); }
#colar fieldset.temperamento label { display: flex; align-items: center; gap: .6rem;
  min-height: var(--alvo); font-size: .9rem; line-height: 1.35; color: var(--tinta); cursor: pointer; }
/* O rádio NÃO é o campo de link: desfaz o `display:block; width:100%` e o
   cromo de campo de texto que a regra `#colar input` lhe daria. */
#colar fieldset.temperamento input[type="radio"] { display: inline-block; flex: none; width: 1.15rem; height: 1.15rem;
  margin: 0; padding: 0; border: 0; background: none; accent-color: var(--acento); }
#colar fieldset.temperamento input[type="radio"]:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* ── O arquivo, e a prévia que o segura (L-111, spec 17 §3.1) ──────────────
   A prévia não é enfeite: a detecção de duas colunas NÃO funciona, e o texto
   extraído na tela é a única salvaguarda que existe entre um PDF embaralhado
   e a inbox de quem vai ler. Por isso ela ocupa o corpo do painel, rola por
   dentro (como os turnos da conversa, L-81) e deixa os botões presos no pé —
   controle que sai da tela é controle que não existe. */

/* ── A porta do arquivo  (revisão 2026-08-24) ──────────────────────────────
   Antes: o `<input type="file">` NU — «Escolher arquivo · Nenhum arquivo
   escolhido» desenhado pelo sistema, o único pedaço de cromo do app que
   nenhum CSS vestia. Um botão de sistema no meio de um painel de papel.

   Agora o label é a porta inteira: zona tracejada na medida do campo de URL
   acima, com o ícone da bandeja (gramática do GLIFO, traço `currentColor`)
   e os formatos aceitos escritos — a informação que o `accept` sempre teve
   e nenhum olho via. O tracejado diz «aqui entra coisa de fora», o mesmo
   vocabulário do chip «Limpar» dos filtros.

   O input segue vivo dentro do label (ver o comentário no colar.mjs):
   escondido por tamanho e opacidade, nunca por `display:none` — senão o
   teclado o perde. O anel de foco acende no LABEL via `:focus-within`,
   porque o anel do núcleo acenderia num elemento de 1px. */
#colar label.arquivo {
  display: flex; flex-direction: column; align-items: center; gap: .32rem;
  position: relative; margin: .8rem auto 0; max-width: var(--measure);
  padding: 1.05rem 1rem 1.1rem; text-align: center; cursor: pointer;
  border: 1.5px dashed var(--borda-controle); border-radius: var(--raio);
  font-family: var(--sans); color: var(--tinta-2);
  transition: border-color var(--dur-rapida) ease, color var(--dur-rapida) ease,
              background-color var(--dur-rapida) ease;
}
#colar label.arquivo:hover, #colar label.arquivo:focus-within, #colar label.arquivo.arrastando {
  border-color: var(--acento); color: var(--acento);
  background: color-mix(in srgb, var(--acento) 5%, transparent);
}
/* Com um arquivo no ar, a porta diz que é ali: o tracejado fecha e o fundo sobe. */
#colar label.arquivo.arrastando {
  border-style: solid; background: color-mix(in srgb, var(--acento) 12%, transparent);
}
#colar label.arquivo:focus-within { outline: 2px solid var(--foco); outline-offset: 2px; }
#colar .porta-ic { width: 26px; height: 26px; }
#colar .porta-titulo { font-size: .88rem; font-weight: 600; color: inherit; }
#colar .porta-formatos { font-size: .66rem; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--tenue); }
#colar input[type="file"] {
  position: absolute; width: 1px; height: 1px; opacity: 0;
  overflow: hidden; clip-path: inset(50%);
}
#colar-previa { flex: 1 1 auto; min-height: 0; overflow-y: auto;
  max-width: var(--measure); margin-inline: auto; width: 100%; }
#colar-previa[hidden] { display: none; }
#colar-previa-titulo { font-family: var(--sans); font-size: .95rem; font-weight: 600;
  color: var(--tinta); margin: 0 0 .2rem; }
#colar-previa-meta { margin: 0 0 .6rem; }
/* Fonte de corpo e `pre-wrap` porque o que se julga aqui é a leitura: as
   quebras de linha SÃO a evidência de que as colunas se costuraram, e um
   `white-space: normal` esconderia justamente o defeito que a prévia veio
   mostrar. */
#colar-previa-texto { font-family: var(--corpo); font-size: .9rem; line-height: 1.55;
  color: var(--tinta-2); white-space: pre-wrap; overflow-wrap: anywhere;
  border-left: 2px solid var(--regra); padding-left: .7rem; }
#colar .linha { display: flex; align-items: center; gap: .5rem; margin-top: .9rem;
  flex: none; flex-wrap: wrap; }
#colar .linha button[hidden] { display: none; }
/* A frase de erro é a entrega deste recurso (spec §8) e pode ter duas linhas:
   `flex: 1` dá a ela a largura que sobra em vez de espremer os botões. */
#colar .linha .sub { flex: 1; line-height: 1.4; }
/* ── «Publicar» é PRIMÁRIO  (revisão 2026-08-24) ───────────────────────────
   O painel tem uma ação só que importa, e ela vestia a mesma borda cinza do
   «Fechar» ao lado — a tela dizia que publicar e desistir pesavam igual.
   Acento cheio + `--sobre-acento`, como o «Entrar» do login: mesmo papel na
   hierarquia, mesma roupa. O hover NÃO herda o de `.btn` (que troca a tinta
   para o acento — invisível sobre o próprio acento): clareia, como o Entrar.

   A ordem visual vem por `order`, sem tocar no DOM: confirmação à direita,
   como todo sheet do iPadOS — e o foco do teclado continua na ordem do
   documento, que ninguém reordenou. */
#colar #colar-publicar, #colar #colar-previa-publicar {
  background: var(--acento); color: var(--sobre-acento);
  border-color: transparent; font-weight: 600; padding: .38rem 1.1rem;
  order: 4;
}
#colar #colar-publicar:hover, #colar #colar-publicar:focus-visible,
#colar #colar-previa-publicar:hover, #colar #colar-previa-publicar:focus-visible {
  color: var(--sobre-acento); border-color: transparent; filter: brightness(1.08);
}
#colar #colar-previa-descartar { order: 3; }
#colar #colar-fechar { order: 2; }
#colar #colar-publicar[disabled], #colar #colar-previa-publicar[disabled] { opacity: .55; filter: none; }

/* O gatilho, no cabeçalho da inbox. É BOTÃO e não campo — `desenhar()`
   repinta o cabeçalho inteiro a cada 30s (`inbox.mjs:406`), e botão não tem
   estado a perder. A linha alinha pela base para o rótulo do botão assentar
   na do título, e não no meio dele. */
.titulo-inbox { display: flex; align-items: center; justify-content: space-between;
  gap: .8rem; }
.titulo-inbox h1 { margin-bottom: 0; }

/* ── O botão de entrada ─────────────────────────────────────────────────────
   A versão anterior era um `.btn` com rótulo «＋ Ler», e ela errava em
   hierarquia: ficava idêntica às abas de status logo abaixo — quatro
   retângulos com a mesma borda —, de modo que a AÇÃO da tela pesava o mesmo
   que os FILTROS. Numa página que é tipografia sobre papel, era também o
   único objeto com cara de formulário.

   ── Quadrado de canto arredondado, não disco  (2026-08-24) ────────────────
   Foi disco («círculo quer dizer coisa que se faz», como o `#caneta`) e
   Yuri o reprovou OVAL: o `border-radius:50%` nunca desenhou círculo aqui,
   porque o `min-height:44px` do núcleo (`:where(button…)`) vence o
   `height:30px` — a caixa real era 30×44. É a MESMA armadilha que o
   comentário de `.linha-progresso .redondo` já registrava («min-height
   vence height e o círculo vira elipse»), e este botão nunca recebeu a
   exceção. A forma nova resolve o defeito e ganha parentesco melhor: o
   quadrado de canto arredondado é a forma do GLIFO da marca no outro lado
   do mesmo cabeçalho (30px, raio 9) e a do próprio ícone do app — os dois
   selos de acento da tela agora são a mesma família, um diz «Leitor», o
   outro diz «entra coisa aqui». O raio segue a proporção do glifo (9/30).

   É o ÚNICO ponto saturado da tela, e isso é a decisão: todo o resto é tinta
   sobre papel, então a cor marca a única coisa que se pode fazer. O `+` sem
   rótulo se sustenta porque é ícone consagrado para «acrescentar» — o veto da
   §5.2 é a ícone INVENTADO, e o nome acessível continua inteiro no
   `aria-label`. */
.entrada {
  flex: none; display: grid; place-items: center;
  /* 30px, e não 34: a 34 o botão competia com a altura do «Inbox» em vez de
     servi-lo. O controle é a ação da tela, não o assunto dela. O
     `min-height` explícito é a exceção ao `--alvo` do núcleo — sem ele a
     caixa estica para 44px e a forma vira oval; a exceção é legítima pela
     mesma razão dos `.redondo` da lista: o alvo real do gesto continua
     confortável no cabeçalho, sem vizinho a meio dedo de distância. */
  width: 30px; height: 30px; min-height: 30px; border-radius: 9px;
  border: none; cursor: pointer;
  background: var(--acento); color: var(--sobre-acento);
  font: 500 1.25rem/1 var(--sans);
  /* O glifo `+` assenta alto na caixa da fonte; 1px o traz ao centro óptico. */
  padding-bottom: 1px;
  transition: transform .12s ease, filter .12s ease;
}
.entrada:hover { filter: brightness(1.12); }
.entrada:active { transform: scale(.94); }
@media (prefers-reduced-motion: reduce) { .entrada { transition: none; } }

/* ── A lupa, ao lado do `+`  (02/09) ───────────────────────────────────────
   Mesma forma e mesma caixa do botão de entrada — são os dois controles do
   cabeçalho da lista —, e a hierarquia entre eles é de PESO: o `+` é a ação
   que traz coisa nova e veste o acento cheio; a lupa é o caminho até o que já
   está lá, e veste aro fino sobre papel. Cheia, ela empataria com o `+` e a
   tela passaria a ter duas ações principais.

   `text-decoration: none` porque agora é um `<a>`: link que leva a uma tela é
   o que o roteador, o «abrir em nova aba» e o teclado já sabem tratar. */
.entrada.lupa {
  background: var(--papel-elev); color: var(--tinta-2);
  border: 1px solid var(--aro-fino); text-decoration: none;
  padding-bottom: 0;
}
.entrada.lupa svg { width: 17px; height: 17px; display: block; }
.entrada.lupa:hover, .entrada.lupa:focus-visible {
  filter: none; color: var(--acento); border-color: var(--acento);
}

/* ── O resultado da busca de artigos  (02/09) ──────────────────────────────
   Agrupado por estado — «Lendo», «Não lidos», «Lidos», «Arquivados» —, na
   gramática que os Destaques já usam para o cabeçalho de cluster: uma LINHA
   com nome, contagem e régua embaixo, e não um cartão em volta. O que a busca
   devolve são cartões; um cartão em volta de cartões é uma moldura a mais. */
/* ── `--measure` está em `em`, e isso morde quem tem fonte menor  (02/09) ──
   `--measure: calc(34.5em * var(--fator-espaco))` mede em EM, relativo à fonte
   do próprio elemento — é o que faz a medida de linha valer 34,5 caracteres em
   qualquer tamanho de texto, que é a razão de ela existir.

   O efeito colateral aparece quando o token vira `max-width` de um bloco com
   fonte MENOR: a contagem do resultado é `.sub` (.82rem), e 34,5em ali deram
   453px contra os 707 dos grupos ao lado — a linha «3 artigos» nascia recuada
   sozinha no meio da coluna.

   Aqui nenhum dos três precisa do teto: o `main` já limita a coluna, e o que
   estes blocos querem é a largura do irmão de cima. Quem mede LINHA usa o
   token; quem só quer acompanhar a coluna herda do pai. */
.busca-artigos { margin: 0 0 1rem; }
.conta-busca { margin: 0 0 .9rem; }
.grupo-busca { margin: 0 0 1.6rem; }
.grupo-busca > h2 {
  display: flex; align-items: baseline; gap: 9px;
  font-family: var(--sans); font-size: 12.5px; font-weight: 600; color: var(--tinta);
  margin: 0 0 14px; padding-bottom: 9px; border-bottom: 1px solid var(--regra);
}
/* ── O pé da página de destaques  (02/09) ─────────────────────────────────
   «Mostrando 200 de 1430» à esquerda e o botão à direita: o número diz onde a
   lista está, e o botão diz o que fazer com isso. Separados por `auto`, e não
   centrados, porque a leitura é «quanto» → «e daí» — a mesma ordem da linha de
   estado dos cartões. */
.mais-destaques {
  max-width: var(--measure); margin: .4rem auto 2rem;
  display: flex; align-items: center; gap: .8rem;
}
.mais-destaques .sub { flex: 1; min-width: 0; }
.mais-destaques .btn { flex: none; }

.grupo-busca > h2 .conta {
  margin-left: auto; font-size: 11.5px; font-weight: 400; color: var(--tenue);
  font-variant-numeric: tabular-nums;
}

/* O botão de perguntar no rodapé do artigo acompanha os três de `montarAcoes`,
   mas não é um deles: leva rótulo escrito porque não tem ícone consagrado, e
   um ícone inventado seria o defeito que a §5.2 já nomeou uma vez — a ação
   que existe e não é encontrada. */
.artigo > footer .acoes .btn.ia { border-color: var(--cromo-acento); color: var(--cromo-acento); }

/* A amostra do controle de marginália mostra o próprio efeito, como as outras
   cinco: uma coluna sozinha, ou uma coluna com o filete da margem ao lado. */
#ajustes .am-marg { display: inline-flex; gap: 2px; align-items: stretch; height: 15px; }
#ajustes .am-marg i { display: block; width: 9px; background: var(--tinta-2); border-radius: 1px; }
#ajustes .am-marg i + i { width: 4px; background: var(--regra); }
#ajustes .am-marg[data-m="nao"] i + i { display: none; }
/* O controle «Notas» aparece em toda largura desde o trilho (28/08): abaixo
   do limiar ele passou a ligar alguma coisa — os marcadores — e um controle
   que só existe em paisagem deixaria o retrato sem como desligá-los. */
#ajustes .grupo[data-grupo="marginalia"] { display: flex; }

/* ── marginália: as notas na margem (L-74, spec 13 §3) ─────────────────────
   A nota volta para onde a anotação esteve por mil anos antes de virar um
   painel que se abre. **A `--measure` não muda** — o painel ocupa a folga que
   já sobrava ao lado da coluna, e não um pedaço da leitura (01: estética de
   leitura é inegociável).

   Todo o layout é CSS, comandado pelo `data-marginalia` do `<html>`. Nenhum
   JavaScript mede coluna nem margem: o que o JS calcula é só a ALTURA de cada
   nota, que depende do texto e não da tela. */
:root {
  /* ── Em `rem`, e isto é correção de defeito, não gosto  (L-74) ────────────
     Estavam em `em`, e `em` resolve contra a fonte do ELEMENTO. A mesma
     variável era lida em dois lugares com fontes diferentes — no `<main>`,
     contra a fonte de leitura; dentro do painel, contra os .78rem dele — e o
     `<main>` reservava mais espaço do que o painel ocupava. A sobra virava um
     vão entre o texto e a nota, que crescia junto com o tamanho do texto.
     `rem` resolve contra a raiz e vale o mesmo nos dois lados da conta. */
  --marg-largura: 14rem;
  --marg-vao: 1rem;
}

/* Fora do limiar o painel não existe — nem ele, nem o controle que o liga
   (ver `#ajustes`). Some sozinho, sem aviso e sem estado a lembrar: um painel
   que pedisse para ser fechado ao girar o iPad seria um diálogo no meio da
   leitura. O limiar é em `em` e não em px porque a medida é em `em`, e o
   leitor muda o tamanho do texto. */
#marginalia { display: none; }

@media (min-width: 56em) {
  /* A composição é coluna + vão + painel, e é ELA que fica centrada. Com a
     coluna centrada, a folga se dividiria em duas e o painel herdaria metade
     — larga demais para nada, estreita demais para uma nota. */
  /* ── Grade, e não conta de largura  (L-74, correção) ─────────────────────
     A primeira versão prendia o painel à borda do `<main>` e confiava numa
     `max-width` calculada para que essa borda caísse logo depois da folha.
     Conta que precisa fechar é conta que uma hora não fecha: bastava a
     largura efetiva do `<main>` diferir da prevista — por viewport, por
     tamanho de texto, por arredondamento — e o painel afastava-se da folha
     sem que nada no CSS dissesse isso.

     Duas colunas resolvem por construção. O painel é **vizinho** da folha,
     não um elemento pendurado numa borda que se espera no lugar certo: o vão
     é o `gap`, e nenhuma aritmética o produz. */
  /* ── Escopado à ROTA, e não só à preferência ─────────────────────────────
     O `<main>` é a raiz de TODAS as telas — inbox, destaques, artigo. Um
     `display: grid` solto nele partiu a inbox em duas colunas, com os cartões
     espremidos na faixa de 14rem reservada para as notas. A grade vale só
     onde há folha ao lado da qual pousar.

     E o `max-width` saiu daqui: `body[data-leitura] main` já declara
     `max-width: none` com especificidade maior, então a conta que eu escrevia
     nunca valeu — era ela que deixava o painel ir para a borda da tela. Com
     a grade não há conta: `justify-content: center` centra as duas faixas. */
  [data-marginalia="sim"] body[data-leitura] main {
    display: grid;
    grid-template-columns: minmax(0, auto) var(--marg-largura);
    gap: var(--marg-vao);
    align-items: start;
    justify-content: center;
  }
  [data-marginalia="sim"] body[data-leitura] .artigo {
    margin-inline: 0;
    padding-right: 1.5rem;
    max-width: calc(var(--measure) + var(--respiro) + 1.5rem);
    /* ── A coluna, DECLARADA  (03/09) ─────────────────────────────────────
       Prender um filho não diz nada sobre o seguinte. A trilha do estudo já
       era `grid-column: 1`, e o auto-posicionamento punha a folha na célula
       livre à direita — a da margem: no Mac do Yuri o artigo apareceu numa
       tira de 224px com o título quebrando uma palavra por linha, e o painel
       da marginália ocupando os 492px do texto. Numa grade que recebe filhos
       de mais de uma rota, cada um diz onde mora. */
    grid-column: 1;
  }

  /* ── O painel e as marcas medem a partir do MESMO elemento ───────────────
     O painel é filho do `<main>` (é o que sobrevive ao `raiz.innerHTML` que
     redesenha o artigo), então é o `<main>` que vira o bloco de contenção.
     Isso alinha os dois lados da conta: `offsetTop` de uma marca também passa
     a ser medido a partir daqui, porque `offsetParent` é o ancestral
     posicionado mais próximo. Pendurar o painel na `.prosa` enquanto o JS
     mede contra o `<main>` foi exatamente o defeito da primeira tentativa —
     o painel saía da tela. */
  /* O `<main>` continua sendo a origem da conta de ALTURA: `offsetTop` de uma
     marca é medido a partir do ancestral posicionado mais próximo, e o painel
     começa no topo da mesma linha da grade. Os dois lados da conta partem do
     mesmo zero. */
  [data-marginalia="sim"] body[data-leitura] main { position: relative; }
  [data-marginalia="sim"] body[data-leitura] #marginalia {
    display: block; position: relative;
    font-family: var(--sans); font-size: .78rem; line-height: 1.5;
    grid-column: 2;
  }

  /* ── Na rota do ESTUDO a grade tem três filhos, e uma linha a mais ────────
     A trilha ocupa a primeira linha sozinha; a folha e o painel dividem a
     segunda. As duas LINHAS são declaradas porque o painel mede a altura das
     notas por `offsetTop` a partir do `<main>`: se ele começasse na linha da
     trilha e a folha na de baixo, toda nota nasceria deslocada pela altura da
     trilha. Fora do estudo não há trilha, e nada disto se aplica — daí a
     qualificação pela rota, em vez de linhas fixas para todo mundo. */
  [data-marginalia="sim"] body[data-rota="estudo"] .trilha { grid-row: 1; }
  [data-marginalia="sim"] body[data-rota="estudo"] .artigo,
  [data-marginalia="sim"] body[data-rota="estudo"] .antessala,
  [data-marginalia="sim"] body[data-rota="estudo"] .erro-estudo,
  [data-marginalia="sim"] body[data-rota="estudo"] #marginalia { grid-row: 2; }
}

/* Os dois trilhos partem do topo. O de baixo não empurra o de cima porque
   ambos são absolutos — quem impede a colisão é o `piso` do posicionador, que
   mede o bloco de cima e começa o de baixo depois dele. */
#marginalia .marg-sem-ancora,
#marginalia .marg-ancoradas { position: absolute; top: 0; left: 0; right: 0; }
/* ── O bloco não nasce atrás do cabeçalho vivo  (spec 64 §2.4) ─────────────
   `.marg-sem-ancora` começa no topo do `<main>` — e no capítulo de livro o
   `.cabecalho-vivo` é `position: fixed`, opaco e mede 61 px ali por cima. O
   rótulo e as duas primeiras linhas da primeira nota ficavam invisíveis, e
   foi assim que o defeito chegou em 19/09 numa captura do dono.

   A altura é MEDIDA (`--cabecalho-h`, escrita por `repintarMargem`) e não
   cravada: ela depende de `--alvo` e da área de segurança do aparelho. Sem a
   variável — artigo avulso, onde não há cabeçalho vivo — vale zero. */
#marginalia .marg-sem-ancora { padding-top: var(--cabecalho-h, 0px); }
#marginalia .marg-sem-ancora .rotulo {
  margin: 0 0 .4rem; color: var(--tinta-2); text-transform: uppercase;
  letter-spacing: .06em; font-size: .68rem;
}
#marginalia .marg-sem-ancora .marg-nota { position: static; margin-bottom: .6rem; }

#marginalia .marg-nota {
  position: absolute; left: 0; right: 0;
  color: var(--tinta-2); cursor: pointer;
  /* O filete na cor do destaque é o que liga a nota ao trecho sem uma linha
     desenhada atravessando a página. */
  border-left: 2px solid var(--hl-cor, var(--regra));
  padding: .1rem 0 .1rem .6rem;
  transition: color .15s ease, border-color .15s ease;
}
#marginalia .marg-nota[data-cor="roxo"]    { --hl-cor: var(--vivo-roxo); }
#marginalia .marg-nota[data-cor="amarelo"] { --hl-cor: var(--vivo-amarelo); }
#marginalia .marg-nota[data-cor="rosa"]    { --hl-cor: var(--vivo-rosa); }
#marginalia .marg-nota[data-cor="azul"]    { --hl-cor: var(--vivo-azul); }
#marginalia .marg-nota p { margin: 0; }
/* A pergunta da conversa vem antes da resposta, e mais apagada: ela é o que
   você perguntou, não o que se quer reler. */
#marginalia .marg-nota .p { font-weight: 600; color: var(--tinta); margin-bottom: .15rem; }
/* O que a máquina escreveu se distingue sem escrever "IA" em lugar nenhum. */
#marginalia .marg-nota[data-origem] .t { font-style: italic; }
#marginalia .marg-nota:hover,
#marginalia .marg-nota:focus-visible { color: var(--tinta); outline: none; }
#marginalia .marg-nota.acesa { color: var(--tinta); border-left-width: 4px; }

/* ── O trilho de marcadores: a marginália onde ela não cabe  (28/08) ────────
   Abaixo do limiar o painel de 14rem não tem onde existir — a medida não
   encolhe (spec 13 §2.3) — e até aqui a marginália simplesmente não existia
   no iPad em retrato. O que cabe é um TRILHO: um marcador por nota, na
   altura exata em que o cartão pousaria, encostado na borda direita, dentro
   da calha de padding da folha. Vê-se de relance onde há pensamento seu na
   página; o toque salta para o trecho E abre a nota (ver `quandoTocar` na
   tela), porque um marcador não mostra texto nenhum.

   `width < 56em` de propósito: é o MESMO número do painel — os dois lados da
   fronteira declarados com o mesmo limiar, sem faixa morta entre eles. E o
   mesmo `data-marginalia`: trilho e painel são a mesma preferência em duas
   larguras, não dois recursos.

   «Sobre o artigo» fica de fora: aquelas anotações não têm altura no texto,
   e um marcador no trilho apontaria para lugar nenhum. Continuam alcançáveis
   pela conversa, como antes do trilho.

   O alvo é 44px de ALTURA numa régua de ~20px de largura na beirada — alvo
   de borda se acerta rolando o polegar contra o canto, e alargá-lo para
   dentro poria uma superfície tocável por cima da última coluna de texto,
   roubando a seleção. O empilhamento do posicionador passa a espaçar por
   estes 44px medidos, então marcadores nunca se sobrepõem. */
@media (width < 56em) {
  [data-marginalia="sim"] body[data-leitura] main { position: relative; }
  [data-marginalia="sim"] body[data-leitura] #marginalia {
    display: block; position: absolute; top: 0; bottom: 0;
    right: max(.15rem, env(safe-area-inset-right));
    width: 1.1rem;
  }
  #marginalia .marg-sem-ancora { display: none; }
  #marginalia .marg-nota {
    height: 44px; border-left: 0; padding: 0;
    display: grid; place-items: center;
  }
  #marginalia .marg-nota .t,
  #marginalia .marg-nota .p { display: none; }
  /* A bolinha herda a MESMA `--hl-cor` do filete do cartão largo; o anel de
     tinta a 22% é o que a separa do papel quando a cor do destaque é clara. */
  #marginalia .marg-nota::before {
    content: ""; width: .45rem; height: .45rem; border-radius: 50%;
    background: var(--hl-cor, var(--regra));
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--tinta) 22%, transparent);
  }
  #marginalia .marg-nota.acesa::before { width: .7rem; height: .7rem; }
}

/* ── página de destaques: a LISTA DE TEXTOS  (spec 55 §2.1) ──────────────────
   Era a árvore tema → texto → trecho, em `<details>` dentro de `<details>`.
   Virou uma linha por texto: o título em serifa, a contagem à direita, a
   sobrancelha (tipo · autor · tema) embaixo e uma faixa de 3px com a
   proporção das cores — a única pista de «que tipo de marca há aqui» que cabe
   numa linha. A linha inteira é o alvo: é um `<a>`. */
.filtros.dq-filtros { font-family: var(--sans); }
.dq-filtros .chip, .dq-filtros .seg-item { font-family: var(--sans); }
.dq-soma { margin: 0 0 .6rem !important; text-align: left; }
.dq-textos { list-style: none; margin: 0 0 2rem; padding: 0;
  border-top: 1px solid var(--regra); }
.dq-textos > li { border-bottom: 1px solid var(--regra); }
.dq-texto {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 1rem; row-gap: 4px;
  padding: 14px 6px 12px; color: inherit; text-decoration: none; border-radius: 6px;
}
.dq-texto:hover, .dq-texto:focus-visible { background: var(--papel-elev); }
.dq-texto:hover .dq-titulo { color: var(--acento); }
.dq-titulo {
  grid-column: 1; font-family: var(--serif); font-size: 16px; font-weight: 600;
  line-height: 1.35; color: var(--tinta); text-wrap: pretty;
}
.dq-titulo .sub { font-weight: 400; font-style: italic; }
.dq-conta {
  grid-column: 2; grid-row: 1; align-self: baseline; justify-self: end; font-family: var(--sans);
  font-size: 13px; color: var(--tinta-2); font-variant-numeric: tabular-nums;
}
.dq-conta b { font-weight: 600; color: var(--tinta); }
.dq-meta, .dq-sobrancelha {
  font-family: var(--sans); font-size: 12px; color: var(--tenue);
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 6px; min-width: 0;
}
.dq-meta { grid-column: 1; }
.dq-quando { grid-column: 2; grid-row: 2; font-family: var(--sans); font-size: 11.5px; color: var(--tenue);
  text-align: right; white-space: nowrap; }
.dq-tipo { font-weight: 600; letter-spacing: .06em; text-transform: uppercase; font-size: 10.5px; color: var(--tinta-2); }
.dq-sep { color: var(--aro-fino); }
.dq-tema { display: inline-flex; align-items: baseline; gap: 5px; }
.dq-tema .ponto, .dq-filtros .ponto, .dq-filtros-texto .ponto {
  width: 6px; height: 6px; border-radius: 50%; display: inline-block; flex: none;
  background: var(--t, var(--tenue)); align-self: center;
}
.dq-faixa {
  grid-column: 1 / -1; display: flex; gap: 2px; height: 3px; margin-top: 6px;
  border-radius: 2px; overflow: hidden; max-width: 14rem;
}
.dq-faixa i { display: block; min-width: 3px; }
.dq-faixa i[data-cor="roxo"], .ponto[data-cor="roxo"]       { background: var(--vivo-roxo); }
.dq-faixa i[data-cor="amarelo"], .ponto[data-cor="amarelo"] { background: var(--vivo-amarelo); }
.dq-faixa i[data-cor="rosa"], .ponto[data-cor="rosa"]       { background: var(--vivo-rosa); }
.dq-faixa i[data-cor="azul"], .ponto[data-cor="azul"]       { background: var(--vivo-azul); }

/* ── Trechos do dia  (spec 60) ─────────────────────────────────────────────
   O que restou do Memoria: três trechos no topo da lista, em rodízio, só para
   reler. O cartão é o irmão do `.destaque` (papel elevado, filete da cor), mas
   sem pé de pigmento nem ✎/✕ — aqui nada se avalia nem se edita. O texto é o
   protagonista: serifa um ponto acima do cartão da lista, e a proveniência
   embaixo, miúda, como legenda de citação. Tudo em tokens: claro, sépia e
   escuro vêm de graça, e o contraste é o já medido para `--tinta-2`/`--tenue`
   sobre `--papel-elev`. */
#trechos-do-dia:empty { display: none; }
.td { margin: 2px 0 22px; }
.td-cabeca {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: 2px 12px; margin: 0 0 10px;
}
.td-cabeca h2 {
  margin: 0; font-family: var(--sans); font-size: 12px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--tinta-2);
}
.td-data { font-weight: 500; letter-spacing: .01em; text-transform: none; color: var(--tenue); }
.td-roda { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.td-roda p { margin: 0; font-family: var(--sans); font-size: 11.5px; color: var(--tenue); }
/* «Outros» e «Os do dia» (spec 60 §6): a mesma pílula quieta dos cartões,
   ao lado da conta da roda — é ela que o botão faz girar. */
.td-botoes { display: inline-flex; flex-wrap: wrap; gap: 6px; }
.td-botoes .td-acao { padding: 0 12px; font-size: 12px; }
.td-lista { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.td-cartao {
  position: relative; margin: 0; padding: 16px 18px 12px 20px;
  background: var(--papel-elev); border: 1px solid var(--papel-borda-fina);
  border-radius: 10px; box-shadow: var(--sombra-pousada); overflow: hidden;
}
.td-cartao .filete {
  position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--hl-cor, var(--vivo-roxo));
}
.td-cartao[data-cor="roxo"]    { --hl-cor: var(--vivo-roxo); }
.td-cartao[data-cor="amarelo"] { --hl-cor: var(--vivo-amarelo); }
.td-cartao[data-cor="rosa"]    { --hl-cor: var(--vivo-rosa); }
.td-cartao[data-cor="azul"]    { --hl-cor: var(--vivo-azul); }
.td-texto {
  margin: 0; padding: 0; border: 0; font-style: normal;
  font-family: var(--serif); font-size: 16px; line-height: 1.6; color: var(--tinta);
  text-wrap: pretty; overflow-wrap: anywhere;
}
.td-texto p { margin: 0 0 .6em; }
.td-texto p:last-child { margin-bottom: 0; }
.td p.td-nota {
  font-family: var(--sans); font-size: 12.5px; line-height: 1.5; color: var(--tinta-2);
  margin: 10px 0 0; padding-left: 10px; border-left: 2px solid var(--aro-fino);
}
.td p.td-de {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 6px; margin: 10px 0 0;
  font-family: var(--sans); font-size: 12px; line-height: 1.45; color: var(--tenue);
}
.td-obra { font-style: normal; font-weight: 600; color: var(--tinta-2); }
.td-obra .sub { font-weight: 400; font-style: italic; }
.td-acoes { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
/* Os dois alvos são a pílula quieta do «Copiar» da seção, não o `.btn` de
   cromo: em sépia o cromo é um bloco escuro, e seis deles gritariam mais que
   os três trechos. 36px como os `.dq-acoes`: alvo secundário dentro do cartão. */
.td-acao {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer; text-decoration: none;
  font-family: var(--sans); font-size: 12.5px; font-weight: 500; color: var(--tinta-2);
  background: none; border: 1px solid var(--aro-fino); border-radius: 999px;
  padding: 0 14px; min-height: 36px;
}
.td-acao:hover, .td-acao:focus-visible { color: var(--acento); border-color: var(--acento); }
.td-acao svg { width: 14px; height: 14px; flex: none; }
.td-copiar > .ic-copiado { display: none; }
.td-copiar[data-estado="copiado"] > .ic-copiar { display: none; }
.td-copiar[data-estado="copiado"] > .ic-copiado { display: block; }
.td-copiar[data-estado="copiado"] { color: var(--foco); border-color: var(--foco); }
.td-copiar[data-estado="falhou"] { color: var(--perigo); border-color: var(--perigo); }

/* ── Os filtros, recolhidos  (spec 55 §2.3) ───────────────────────────────
   À vista: a busca, o segmentado do tipo e o botão «Filtrar» com a contagem.
   Tema, cor e período moram no painel — e o que está LIGADO fica fora dele,
   como pílula com ✕, porque o filtro esquecido é a armadilha que os chips
   sempre expostos existiam para impedir. */
.dq-controles { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.dq-controles .segmentado { flex: none; }
.dq-abrir { margin-left: auto; cursor: pointer; font-family: var(--sans); }
.dq-abrir[aria-expanded="true"] { border-color: var(--acento); color: var(--acento); }
.dq-n {
  display: inline-grid; place-items: center; min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 999px; background: var(--acento); color: var(--sobre-acento);
  font-size: 10.5px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.dq-ativos { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.dq-ativos .chip.limpar { margin-left: 0; }
.dq-painel {
  margin-top: 12px; padding: 14px 16px 16px; border-radius: 10px;
  background: var(--papel-elev); border: 1px solid var(--papel-borda-fina);
  box-shadow: var(--sombra-pousada);
}
.dq-painel[hidden] { display: none; }
.dq-rotulo {
  font-family: var(--sans); font-size: 10.5px; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--tenue); margin: 12px 0 8px !important;
}
.dq-painel > .dq-rotulo:first-child { margin-top: 0 !important; }
.dq-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

/* ── O calendário do dia  (17/09) ─────────────────────────────────────────
   O controle nativo de data só sabe `min`, `max` e `step` — não sabe desligar
   um dia avulso. Como a regra aqui é exatamente essa (dia sem destaque não é
   botão), a grade é desenhada: sete colunas, o dia marcado com a contagem, o
   vazio ainda no lugar dele e sem alvo. A caixa tem largura máxima porque um
   calendário esticado numa tela larga deixa de parecer um calendário. */
#dq-cal[hidden] { display: none; }
.dq-cal { margin-top: 12px; max-width: 300px; }
.dq-cal-topo { display: flex; align-items: center; gap: 4px; margin: 0 !important; }
.dq-cal-mes {
  flex: 1; display: block; text-align: center; font-family: var(--sans);
  font-size: 12.5px; font-weight: 600; color: var(--tinta-2);
}
.dq-cal-mes::first-letter { text-transform: uppercase; }
.dq-mes {
  flex: none; width: 36px; padding: 0; border: 0; border-radius: 9px; background: none;
  color: var(--tinta-2); font-size: 18px; line-height: 1; cursor: pointer;
}
.dq-mes:hover:not(:disabled), .dq-mes:focus-visible {
  color: var(--acento); background: color-mix(in srgb, var(--acento) 8%, transparent);
}
.dq-mes:disabled { color: var(--tenue); opacity: .45; cursor: default; }
.dq-grade { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.dq-sem {
  font-family: var(--sans); font-size: 10px; font-weight: 700; letter-spacing: .06em;
  color: var(--tenue); text-align: center; padding-bottom: 4px;
}
.dq-dia {
  display: grid; align-content: center; justify-items: center; min-height: 38px;
  border: 1px solid transparent; border-radius: 9px; font-family: var(--sans);
  font-size: 12.5px; font-variant-numeric: tabular-nums; color: var(--tenue);
  text-decoration: none;
}
.dq-dia b { font-weight: 500; }
.dq-dia.tem {
  color: var(--tinta); background: color-mix(in srgb, var(--acento) 8%, transparent);
}
.dq-dia.tem b { font-weight: 600; }
.dq-dia.tem i {
  font-style: normal; font-size: 9.5px; font-weight: 700; line-height: 1.1; color: var(--acento);
}
.dq-dia.tem:hover, .dq-dia.tem:focus-visible { border-color: var(--acento); }
.dq-dia.hoje { border-color: var(--aro-fino); }
.dq-dia.escolhido, .dq-dia.escolhido:hover {
  background: var(--acento); border-color: var(--acento); color: var(--sobre-acento);
}
.dq-dia.escolhido i { color: var(--sobre-acento); }
.dq-dia-abrir { cursor: pointer; font-family: var(--sans); }
.dq-dia-abrir[aria-expanded="true"] { border-color: var(--acento); color: var(--acento); }
.ic-cal { width: 14px; height: 14px; margin-right: 5px; vertical-align: -2px; }
.dq-filtros-texto .chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 11px;
  border: 1px solid var(--aro-fino); border-radius: 999px; font-family: var(--sans);
  font-size: 12px; font-weight: 500; color: var(--tinta-2); text-decoration: none;
  white-space: nowrap; min-height: 0; background: none;
}
.dq-filtros-texto .chip:hover, .dq-filtros-texto .chip:focus-visible { border-color: var(--acento); color: var(--acento); }
.dq-filtros-texto .chip.ativo {
  color: var(--tinta); border-color: color-mix(in srgb, var(--acento) 45%, transparent);
  background: color-mix(in srgb, var(--acento) 9%, var(--papel-elev));
}

/* ── Os achados da busca: trechos sob o nome do texto ─────────────────── */
.dq-achados { margin: 0 0 1.4rem; }
.dq-achados > h2, .dq-secao > h2 {
  display: flex; align-items: center; gap: 10px; margin: 0 0 12px; padding: 8px 0 9px;
  border-bottom: 1px solid var(--regra); font-family: var(--sans); font-size: 13px;
  font-weight: 600; color: var(--tinta);
}
.dq-achados > h2 a { color: inherit; text-decoration: none; font-family: var(--serif); font-size: 14.5px; }
.dq-achados > h2 a:hover { color: var(--acento); }
.dq-achados > h2 .conta, .dq-secao > h2 .conta {
  font-weight: 400; font-size: 12px; color: var(--tenue); font-variant-numeric: tabular-nums;
}

/* ── A página de UM texto  (spec 55 §2.2) ─────────────────────────────────
   Mais larga que a coluna de leitura quando há sumário: o sumário mora à
   esquerda, grudado no topo, e a coluna dos trechos mantém a medida. Abaixo de
   60rem o sumário deita numa fileira rolável sobre os trechos. */
body[data-rota="destaques-texto"] main { max-width: calc(var(--measure) + 15rem); }
.dq-volta { margin: 0 0 10px; font-family: var(--sans); font-size: 13px; }
.dq-volta a { color: var(--tinta-2); text-decoration: none; }
.dq-volta a:hover { color: var(--acento); }
.dq-cabeca { margin: 0 0 14px; }
.dq-cabeca h1 { margin: 4px 0 2px; text-wrap: balance; }
.dq-autor { font-family: var(--serif); font-style: italic; color: var(--tinta-2); margin: 0 0 6px !important; }
.dq-acoes { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.dq-acoes .btn { display: inline-flex; align-items: center; gap: 7px; text-decoration: none; min-height: 36px; }
.dq-acoes .btn svg, .dq-copiar-secao svg { width: 15px; height: 15px; flex: none; }
.dq-filtros-texto { margin: 0 0 18px; }
.dq-corpo.com-sumario { display: grid; grid-template-columns: 13rem minmax(0, var(--measure)); gap: 0 2.2rem; align-items: start; }
.dq-sumario { position: sticky; top: 1rem; max-height: calc(100vh - 2rem); overflow-y: auto; font-family: var(--sans); }
.dq-sumario ol { list-style: none; margin: 0; padding: 0; }
.dq-sumario a {
  display: flex; gap: 8px; align-items: baseline; padding: 6px 8px; border-radius: 6px;
  font-size: 12.5px; color: var(--tinta-2); text-decoration: none; min-height: 0;
}
.dq-sumario a:hover, .dq-sumario a:focus-visible { background: var(--papel-elev); color: var(--acento); }
.dq-sumario .t { flex: 1; min-width: 0; line-height: 1.35; }
.dq-sumario .n { color: var(--tenue); font-variant-numeric: tabular-nums; font-size: 11.5px; }
.dq-secao { margin: 0 0 1.6rem; scroll-margin-top: 1rem; }
.dq-secao > h2 .t { font-family: var(--serif); font-size: 15px; }
.dq-copiar-secao {
  margin-left: auto; display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-family: var(--sans); font-size: 12px; font-weight: 500; color: var(--tinta-2);
  background: none; border: 1px solid var(--aro-fino); border-radius: 999px;
  padding: 4px 10px; min-height: 0;
}
.dq-copiar-secao:hover, .dq-copiar-secao:focus-visible { color: var(--acento); border-color: var(--acento); }
@media (max-width: 60rem) {
  .dq-corpo.com-sumario { display: block; }
  .dq-sumario { position: static; max-height: none; overflow-x: auto; margin: 0 0 16px;
    -webkit-overflow-scrolling: touch; }
  .dq-sumario .dq-rotulo { display: none; }
  .dq-sumario ol { display: flex; gap: 6px; }
  .dq-sumario li { flex: none; }
  .dq-sumario a { border: 1px solid var(--aro-fino); border-radius: 999px; padding: 5px 11px; white-space: nowrap; }
  .dq-sumario .t { flex: none; }
}

/* O ✓ do copiar: as duas folhas nascem juntas e o estado escolhe qual se vê —
   a mesma gramática do botão da cerca de código. */
:is(.destaque .copiar, [data-copiar-tudo], .dq-copiar-secao) > .ic-copiado { display: none; }
:is(.destaque .copiar, [data-copiar-tudo], .dq-copiar-secao)[data-estado="copiado"] > .ic-copiar { display: none; }
:is(.destaque .copiar, [data-copiar-tudo], .dq-copiar-secao)[data-estado="copiado"] > .ic-copiado { display: block; }
:is(.destaque .pe .copiar, [data-copiar-tudo], .dq-copiar-secao)[data-estado="copiado"] { color: var(--foco); border-color: var(--foco); }
:is(.destaque .pe .copiar, [data-copiar-tudo], .dq-copiar-secao)[data-estado="falhou"] { color: var(--perigo); border-color: var(--perigo); }

.destaques { list-style: none; margin: 0 0 1rem; padding: 0;
  display: flex; flex-direction: column; gap: 9px; }
/* ── O destaque virou CARTÃO, e o filete entrou nele  (02/09) ──────────────
   Era uma linha com filete à esquerda, direto sobre a mesa. Com o agrupador
   deixando de ser cartão, a superfície desceu um nível: quem é objeto aqui é o
   trecho marcado, e é ele que ganha papel, borda fina e sombra.

   O filete leva a cor do destaque: aqui ele identifica a marca, ao contrário
   do filete de margem no TEXTO, que a §5.1 descartou por marcar o parágrafo
   inteiro. Numa lista, o item É o destaque — não há discrepância possível.
   `overflow: hidden` para o raio cortá-lo nos cantos, como no `.item`. */
.destaque {
  position: relative; padding: 14px 18px 12px; margin: 0;
  background: var(--papel-elev); border: 1px solid var(--papel-borda-fina);
  border-radius: 10px; box-shadow: var(--sombra-pousada); overflow: hidden;
}
.destaque .filete {
  position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--hl-cor, var(--hl-roxo));
}
.destaque[data-cor="roxo"]    { --hl-cor: var(--vivo-roxo); }
.destaque[data-cor="amarelo"] { --hl-cor: var(--vivo-amarelo); }
.destaque[data-cor="rosa"]    { --hl-cor: var(--vivo-rosa); }
.destaque[data-cor="azul"]    { --hl-cor: var(--vivo-azul); }
/* Sem min-height explícito de propósito: é `<a href>` de verdade — navega até
   o trecho no artigo —, então o alvo de toque não é rótulo, é a linha
   inteira. Já herda os 44px do `--alvo` do núcleo (`:where(...,a[href])`),
   e nada aqui redeclara `min-height` para vencer essa herança. Verificado:
   `.destaque` (o pai) não tem altura fixa nem `overflow` que corte a caixa. */
.destaque .trecho {
  display: block; color: var(--tinta); text-decoration: none;
  font-family: var(--serif); font-weight: 400; font-size: 15px; line-height: 1.6;
  text-wrap: pretty;
}
.destaque .trecho:hover { color: var(--acento); }
/* ── O pé do cartão: pigmento, nota e os dois alvos  (02/09) ───────────────
   O rótulo do pigmento em PALAVRA é o ganho que não é estético: a cor do
   destaque significa alguma coisa (importante / vale citar / suspeito /
   estrutural), e até aqui essa semântica só existia na cabeça de quem marcou.
   Quem relê um mês depois lê a palavra. */
.destaque .pe {
  display: flex; align-items: center; gap: 8px; margin-top: 12px;
  font-family: var(--sans); min-width: 0;
}
.destaque .pigmento {
  font-size: 11px; font-weight: 500; letter-spacing: .09em; text-transform: uppercase;
  color: var(--tenue); flex: none;
}
.destaque .pe .divisa { width: 1px; height: 12px; background: var(--aro-fino); flex: none; }
/* A nota ganhou linha própria (spec 55): cortada em reticências no pé, ela
   era ilegível justamente quando existia; e o «sem nota» ocupava o pé de
   todos os cartões para dizer uma ausência. */
.destaque .nota-texto {
  font-family: var(--sans); font-size: 12.5px; line-height: 1.5; color: var(--tinta-2);
  margin: 8px 0 0; padding-left: 10px; border-left: 2px solid var(--aro-fino);
}
/* A pergunta da IA (19/09) em cima da resposta, no mesmo fio: os dois são um
   turno só. Em peso, como a `.p` da margem do texto — é quem pergunta. */
.destaque .dq-pergunta, .td p.td-pergunta {
  font-family: var(--sans); font-size: 12.5px; line-height: 1.5; font-weight: 600;
  color: var(--tinta); margin: 8px 0 0; padding-left: 10px; border-left: 2px solid var(--aro-fino);
}
.td p.td-pergunta { margin-top: 10px; }
:is(.destaque .dq-pergunta + .nota-texto, .td p.td-pergunta + .td-nota) { margin-top: 0; padding-top: 4px; }
.destaque .quando { font-family: var(--sans); font-size: 11px; color: var(--tenue); }
.destaque .dq-de { font-family: var(--sans); font-size: 11.5px; color: var(--tenue); margin: 0 0 4px; }
.destaque .pe .copiar svg { width: 13px; height: 13px; }
.destaque .pe .acoes { margin-left: auto; display: flex; gap: 5px; flex: none; }
/* 26px, e `min-height` explícito pela mesma razão de sempre: sem ele o
   `--alvo` de 44px do núcleo vence o `height` e o círculo vira elipse. A
   exceção é a de sempre — alvo secundário dentro de um cartão cuja linha
   inteira já é alvo conforme. */
.destaque .pe .redondo {
  width: 26px; height: 26px; min-height: 26px; font-size: 12px;
}
/* A tinta é a do CROMO, que o `.redondo` já dá (19/09). Esta regra ainda
   dizia `color: var(--tenue)` e a borda em `--aro-fino` — o par do botão
   VAZADO de antes de 04/09. Quando o redondo virou grafite, o glifo ficou
   cinza de papel sobre campo escuro, e o ✎ e o ✕ quase sumiam. Os estados
   seguem a mesma troca: `--foco` e `--perigo` são tintas de papel, e sobre o
   grafite quem se lê é `--cromo-acento` e `--cromo-perigo`. Vêm DEPOIS do
   `:is(...)[data-estado]` lá de cima, com o mesmo peso, e por isso vencem. */
.destaque .pe .copiar[data-estado="copiado"] { color: var(--cromo-acento); border-color: var(--cromo-acento); }
.destaque .pe .copiar[data-estado="falhou"],
.destaque .pe .x:hover, .destaque .pe .x:focus-visible {
  color: var(--cromo-perigo); border-color: var(--cromo-perigo);
}
.destaque .selo {
  font-family: var(--sans); font-size: .72rem; color: var(--tinta-2);
  margin: .3rem 0 0; opacity: .85;
}
.destaque .selo::before { content: "⚠ "; }
/* O ✕ é o segundo caminho de desmarcar (03 §5.2): na lista, o item some na
   frente de quem apagou — é o caminho que se acha sem procurar. Em 02/09 ele
   saiu do canto absoluto e desceu para o pé do cartão, ao lado do `✎` que
   abre a nota: os dois são o que se faz COM o trecho, e o que se faz com uma
   coisa mora junto dela, não flutuando sobre a quina. */

/* O pulso do salto de volta: o olho precisa de onde pousar depois de rolar
   vários parágrafos. Duas piscadas curtas, e só. */
/* Era `animation` numa `<mark>`, com o `.4s ease 2` literal e a nota que
   explicava o literal; na spec 45 quem pisca é o REGISTRO — `pigmento.pulsar()`
   põe e tira o trecho deste nome duas vezes, a 380ms. `::highlight` não anima,
   e o efeito é o mesmo porque o pulso sempre foi ligar e desligar uma cor, não
   interpolar nada. A cadência continua sendo escolhida a olho, e agora mora em
   `PULSO_MS`/`PULSO_VEZES` no `pigmento.mjs`, junto de quem a executa.

   `prefers-reduced-motion` perdeu a regra própria: sem animação, o que resta
   são duas trocas de cor — que é exatamente o que a preferência pedia no lugar
   da animação. */
::highlight(destaque-pulso) {
  background-color: color-mix(in srgb, var(--acento) 45%, var(--hl-amarelo));
}

/* ── O pulso do BLOCO  (L-123) ─────────────────────────────────────────────
   O salto da busca no texto pousa num parágrafo que ninguém marcou, e a
   animação acima não serve: ela interpola a partir de `--hl-cor`, que é a cor
   do destaque e não existe fora de uma `<mark>`. Sem custom property, o
   `background-color` inicial resolveria para `transparent` e as duas piscadas
   seriam uma só, no fim.

   Mesma cadência (duas piscadas, .4s ease), mesma razão de ser literal, e o
   mesmo respeito ao `prefers-reduced-motion` — ali o realce é estático, e não
   ausente: quem pediu menos movimento também precisa achar o parágrafo. */
@keyframes leitor-pulso-bloco {
  0%, 100% { background-color: transparent; }
  50% { background-color: color-mix(in srgb, var(--acento) 18%, transparent); }
}
.prosa [data-bid].pulsa {
  animation: leitor-pulso-bloco .4s ease 2;
  border-radius: var(--raio-p);
}
@media (prefers-reduced-motion: reduce) {
  .prosa [data-bid].pulsa {
    animation: none;
    background-color: color-mix(in srgb, var(--acento) 12%, transparent);
  }
}

/* ── As passagens do texto, na busca  (L-123) ──────────────────────────────
   Terceiro nível da mesma família de `<details>` da tela — cluster, artigo e
   agora isto —, mas visualmente SUBORDINADO aos dois: borda tracejada e
   sobrancelha tênue. A hierarquia é a mensagem: em cima está o que a mão
   marcou, aqui o que só passou pelos olhos. Um cartão com o mesmo peso dos
   grupos de destaque diluiria o acervo curado do leitor no acervo inteiro. */
.passagens {
  margin-top: 1.6rem; padding-top: 1.1rem;
  border-top: 1px dashed var(--regra);
}
.passagens > summary {
  display: flex; align-items: baseline; gap: .6rem; cursor: pointer;
  font-family: var(--sans);
}
.passagens > summary .titulo {
  font-size: .68rem; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--tenue);
}
.passagens > summary .conta { font-size: .78rem; color: var(--tenue); }
.passagens > .sub { margin: .3rem 0 .8rem; }
.passagens ul { list-style: none; margin: 0; padding: 0; }

.passagem a {
  display: block; padding: .6rem .7rem; border-radius: var(--raio-p);
  text-decoration: none; color: inherit;
  border: 1px solid transparent;
}
.passagem a:hover, .passagem a:focus-visible {
  background: var(--papel-elev); border-color: var(--regra);
}
/* O título do artigo vem ANTES do trecho, e menor: a pergunta que a lista
   responde é «onde eu li isso», e a resposta é o nome do texto. */
.passagem .onde {
  display: block; font-family: var(--sans); font-size: .72rem;
  color: var(--tenue); margin-bottom: .2rem;
}
/* O trecho na SERIFADA da leitura, não na sans do cromo: é prosa do artigo
   citada aqui dentro, e ler no mesmo tipo em que se leu ajuda a reconhecer. */
.passagem .texto {
  display: block; font-family: var(--serif); font-size: .92rem; line-height: 1.5;
  color: var(--tinta-2);
}
.passagem .texto mark {
  background: color-mix(in srgb, var(--acento) 22%, transparent);
  color: inherit; border-radius: 2px; padding: 0 .1em;
}

/* ── filtros dos destaques (L-55) ──────────────────────────────────────────
   Chips no lugar dos menus que a §7.1 desenha: menu no iPad é um toque a mais
   e uma camada sobre o conteúdo, e o que está ativo tem de ficar visível SEM
   abrir nada — é o que impede o filtro esquecido. */
.filtros { max-width: var(--measure); margin: 0 auto 1.4rem; }
/* ── Uma fileira só, e três registros dentro dela  (02/09) ─────────────────
   Eram três `<nav class="linha">` empilhados — cluster, pigmento, período —
   com catorze pastilhas do mesmo peso. Agora é uma fileira: os chips de
   recorte, uma divisa de 1px, e o segmentado do período. `flex-wrap` continua,
   porque num iPhone catorze pastilhas não cabem numa linha e a alternativa
   seria rolagem horizontal escondendo filtro ativo. */
.filtros .linha { display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  font-family: var(--sans); font-size: .78rem; }
.filtros .grupo-chips { display: contents; }
/* A divisa separa registros sem desenhar mais uma caixa. Some quando a
   fileira quebra logo antes dela? Não: ela quebra junto, e um traço no começo
   de uma linha ainda diz «daqui em diante é outra coisa». */
.filtros .divisa {
  width: 1px; height: 20px; background: var(--regra); margin: 0 3px; flex: none;
}
/* ── O chip em repouso é HAIRLINE, e só o ativo se tinge  (02/09) ──────────
   O que havia: fundo `--papel-elev` e borda `--borda-controle` em todos, o
   ativo se distinguindo só pela cor da borda. Catorze superfícies elevadas
   para catorze recortes que ninguém ligou ainda.

   Agora o repouso é transparente com aro fino, e o ATIVO ganha leito na
   própria matiz — a mesma gramática do `.chip` da inbox, que já tinge o ativo
   com `--t` para não dizer «cyber» com a cor do app.

   O aro fino é dispensado do piso de 3:1 pela razão que a nota de
   `--aro-fino` registra: o chip carrega ponto colorido e rótulo em
   `--tinta-2`, e a borda não é a única pista. */
.filtros .chip { display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 12px; border: 1px solid var(--aro-fino); border-radius: 999px;
  font-size: 12px; font-weight: 500;
  color: var(--tinta-2); background: none; text-decoration: none; white-space: nowrap;
  min-height: 0; }
.filtros .chip:hover, .filtros .chip:focus-visible {
  border-color: var(--acento); color: var(--acento); }
.filtros .chip.ativo {
  color: var(--tinta);
  border-color: color-mix(in srgb, var(--t, var(--acento)) 45%, transparent);
  background: color-mix(in srgb, var(--t, var(--acento)) 9%, var(--papel-elev));
}
.filtros .chip.limpar { margin-left: auto; border-style: dashed; }
/* 6px, não 10: no chip hairline o ponto é o acento da peça, e a 10px ele
   competia com o rótulo. Sem aro próprio pelo mesmo motivo — dois contornos
   concêntricos num chip de 12px de texto. */
.filtros .ponto { width: 6px; height: 6px; border-radius: 50%; display: inline-block;
  flex: none; background: var(--t, var(--tenue)); border: 0; }

/* ── O período vira SEGMENTADO  (02/09) ───────────────────────────────────
   Quatro valores mutuamente exclusivos, sempre um deles ligado: é a definição
   de segmentado, e é a peça que as `.abas.seg` da inbox e as `.vistas` da
   estante já usam. Como pastilhas soltas, «Sempre» ligado parecia um filtro
   aplicado — quando é justamente a ausência de filtro. */
.filtros .segmentado {
  display: inline-flex; gap: 2px; padding: 3px; flex: none;
  background: var(--papel-elev-2); border-radius: 999px;
}
.filtros .seg-item {
  font-size: 11.5px; font-weight: 500; color: var(--tinta-2);
  text-decoration: none; padding: 7px 12px; border-radius: 999px;
  white-space: nowrap; min-height: 0;
}
.filtros .seg-item:hover, .filtros .seg-item:focus-visible { color: var(--acento); }
.filtros .seg-item.ativo {
  background: var(--papel-elev); color: var(--tinta); font-weight: 600;
  box-shadow: var(--sombra-pousada);
}
.filtros .ponto[data-cor="roxo"]    { background: var(--vivo-roxo); }
.filtros .ponto[data-cor="amarelo"] { background: var(--vivo-amarelo); }
.filtros .ponto[data-cor="rosa"]    { background: var(--vivo-rosa); }
.filtros .ponto[data-cor="azul"]    { background: var(--vivo-azul); }

/* ── busca nos destaques (L-56, L-68) ──────────────────────────────────────
   A caixa com aro e ícone existe porque um `<input type=search>` sem moldura,
   num app sem barra de navegação no alto, não se lê como campo — se lê como
   uma linha de texto cinza. O aro é a afordância. */
/* Borda em --borda-controle, não --regra (Onda 3, correção — mesmo caso do
   `.item` acima): mora sobre `--tela`, e `--regra` × `--tela` some de novo. O
   aro inteiro É a afordância do campo — a razão pela qual esta regra existe
   —, então é o mesmo controle que `--borda-controle` já cobre. */
/* Borda fina desde 02/09, e a afordância não se perdeu: ela mudou de peça. O
   aro grosso existia porque a caixa não tinha nada que a separasse da mesa —
   agora ela é `--papel-elev` COM sombra, que é a regra que o núcleo escreve
   para qualquer folha («é a sombra que separa a folha da mesa»). A lupa e o
   texto-guia continuam onde estavam. */
/* O seletor perdeu o `.filtros` em 02/09: a estante ganhou a MESMA caixa, e é
   a mesma pergunta em outra tela («onde está isto?»). Duas caixas diferentes
   para uma pergunta só seriam duas coisas na cabeça de quem usa. */
.busca {
  display: flex; align-items: center; gap: 10px; margin: 0 0 14px;
  background: var(--papel-elev); border: 1px solid var(--papel-borda-fina);
  border-radius: 10px; padding: 0 14px; min-height: 44px;
  box-shadow: var(--sombra-pousada);
}
.busca:focus-within { border-color: var(--acento); }
/* SVG desde a revisão 2026-08-24 — mesma razão dos ícones da barra: o "⌕"
   era glifo de texto e saía com peso de traço diferente do resto do cromo. */
.busca .ic { color: var(--tenue); flex: none; display: block; }
.busca .ic svg { width: 17px; height: 17px; display: block; }
.busca input[type="search"] {
  flex: 1; width: 100%; font-family: var(--sans); font-size: .9rem; color: var(--tinta);
  background: none; border: 0; border-radius: 0;
  padding: .6rem 0; -webkit-appearance: none; appearance: none;
}
/* O foco acende a CAIXA, não o campo: o campo já não tem borda própria, e um
   contorno interno dentro de um aro externo são duas molduras concêntricas. */
.busca input[type="search"]:focus-visible { outline: none; }
.busca input[type="search"]::placeholder { color: var(--tenue); }
/* Na estante ela divide a linha com o alternador de vista: `max-width` para não
   esticar até a coluna da capa num Mac de tela larga. */
.busca-estante { max-width: var(--measure); margin: 0 auto 1.1rem; }

/* ── painel de diagnóstico (L-58c) ────────────────────────────────────────
   No iPad não há console: sem isto, todo defeito que só acontece no aparelho
   vira adivinhação. Só existe no DOM quando ligado por `?diag=1`. */
#diag {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 90; max-height: 42vh;
  display: flex; flex-direction: column;
  background: color-mix(in srgb, var(--papel-elev) 94%, transparent);
  /* aresta: painel fixo cobrindo até 42vh por baixo — mesma classe de sheet
     que #ajustes e #nota, ancorado na borda, não pairando sobre a página. */
  border-top: 2px solid var(--acento); box-shadow: var(--sombra-aresta);
  font-family: var(--mono); font-size: 11px; line-height: 1.45; color: var(--tinta);
  padding-bottom: env(safe-area-inset-bottom);
}
#diag .topo { display: flex; align-items: center; gap: .5rem; padding: .4rem .6rem;
  border-bottom: 1px solid var(--regra); }
#diag .topo strong { color: var(--acento); letter-spacing: .04em; }
/* Sem min-height explícito de propósito: são `<button>` de verdade (copiar,
   limpar, fechar) — controles isolados, não rótulos —, então merecem o
   alvo cheio. Já herdam os 44px do `--alvo` do núcleo (`:where(button,…)`)
   porque nada aqui redeclara `min-height`, e `#diag .topo` (o pai) é flex
   com altura livre, sem `overflow` que corte a caixa. */
/* Borda em --borda-controle (§2): background:none — o botão não tem fundo
   próprio, só o do painel atrás dele —, então a borda é a única pista. */
#diag button { margin-left: auto; font: inherit; color: var(--tinta-2);
  background: none; border: 1px solid var(--borda-controle); border-radius: 5px;
  padding: .25rem .5rem; cursor: pointer; }
#diag button + button { margin-left: .3rem; }
#diag .contas { padding: .4rem .6rem; color: var(--acento); word-break: break-all; }
#diag .linhas { padding: 0 .6rem .5rem; overflow-y: auto; white-space: pre-wrap;
  word-break: break-word; color: var(--tinta-2); }

/* ── prévia da seleção (L-58d) ─────────────────────────────────────────────
   Enquanto há seleção nativa viva, o iOS mostra o menu dele (Copiar,
   Consultar) por cima da nossa barra, e o leitor não alcança "Destacar".
   A seleção nativa é o feedback DURANTE o arrasto; terminado o gesto, ela sai
   e esta tinta fica no lugar — diz a mesma coisa e não traz menu junto.

   O tracejado a distingue de um destaque confirmado: é proposta, não fato. */
/* Na spec 45 a prévia deixou de ser um destaque falso com `hlId="__previa__"`
   passado ao pintor e virou nome próprio, pintado por `pigmento.previa()`. A
   cor vem de `--cor-ativa`, que o `usarCor()` já publica no documento — a
   mesma variável que acende o botão da caneta, então as duas não têm como
   discordar. O tracejado trocou `outline` por `underline`, que é o que
   `::highlight()` aceita. */
::highlight(destaque-previa) {
  background-color: color-mix(in srgb, var(--cor-ativa, var(--hl-amarelo)) 55%, transparent);
  text-decoration: underline dashed var(--acento);
  text-decoration-thickness: 1px;
  text-underline-offset: .16em;
}

/* ── os botões redondos: um desenho, dois lugares  (L-70) ──────────────────
   `.redondo` é a forma; quem diz o tamanho é o CONTEXTO, logo abaixo. Antes
   havia dois blocos quase idênticos (`.item .zerar` e `.item .excluir`) e, no
   rodapé do artigo, um `.btn` retangular fazendo o mesmo trabalho com outra
   cara — a divergência que a L-70 foi consertar. Uma classe é o que impede a
   terceira variante.

   Borda em --borda-controle (§2): `background: none` — o botão some no fundo
   do `.item` e no da folha —, então a borda é a única pista de que ali há um
   botão e não um enfeite. */
/* ── E o redondo virou CROMO  (04/09) ─────────────────────────────────────
   Ele era vazado: `background: none` e a borda como única pista de que ali há
   um botão. Passa a ser o mesmo material da lateral, da barra e da pilha — o
   gradiente grafite —, e com isso o app inteiro passa a dizer a mesma coisa
   com a mesma tinta: **página é papel, ferramenta é cromo**. Antes disso a
   regra valia só para o cromo de navegação, e um botão de ação vazado no meio
   de um cartão era a exceção que sobrava.

   O ganho não é só de coerência. Vazado, o `.redondo` dependia da borda para
   existir, e a borda é um fio de `--borda-controle` que num cartão claro
   sobre folha clara é a coisa mais fraca da tela. Cheio, ele se acha de
   relance — e o glifo, que era `--tinta-2` (um cinza de papel), passa a ser a
   tinta do cromo, medida sobre o campo em que de fato está. */
.redondo {
  flex: none; border-radius: 50%; box-sizing: border-box;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--cromo-borda);
  background: linear-gradient(180deg, var(--cromo-1), var(--cromo-2));
  color: var(--cromo-tinta);
  font-family: var(--sans); line-height: 1; cursor: pointer; padding: 0;
}
.redondo:hover, .redondo:focus-visible {
  color: var(--cromo-acento); border-color: var(--cromo-acento);
}
/* ── Ação DESENHADA dentro do botão redondo  (03/09) ───────────────────────
   As outras ações são glifo de texto e herdam o tamanho da fonte; a
   escrivaninha é um SVG (a mesma marca do destino, ver `ICONE_ESCRIVANINHA`),
   e SVG sem tamanho declarado assume 300×150 — o botão viraria uma bolha
   deformada. `block` tira a folga da linha de base, que num `inline` deixaria
   o desenho 3px fora do centro do círculo. */
.redondo svg { width: 58%; height: 58%; display: block; }
.redondo[disabled] { opacity: .5; cursor: default; }

/* ── reler do começo, na inbox (L-53g) ─────────────────────────────────────
   A ação mora aqui, e não no rodapé do artigo: num texto longo, reiniciar
   exigiria rolar até o fim para achar o botão — percorrer justamente o que se
   quer recomeçar. */
.linha-progresso { display: flex; align-items: center; gap: .6rem; }
.linha-progresso .progresso { flex: 1; }

/* 32px na linha da lista. `min-height` sobrepõe o --alvo:44px do núcleo de
   propósito: sem isto, min-height vence height e o círculo vira elipse de
   32×44. A exceção é legítima porque estes são alvos SECUNDÁRIOS dentro do
   `.item`, que já tem área de toque própria bem acima de 44px — não são
   controles isolados. O `.acoes` que os agrupa usa gap .4rem, e não os .6rem
   da linha: a 32px com .6rem entre todos, os quatro (↺ ✓ ⤓ ✕) empurravam o
   crédito para uma segunda linha no iPad em retrato. Os .6rem sobram para
   separar o ↺ — que é ação de progresso — do grupo de estado. */
.linha-progresso .redondo { width: 32px; height: 32px; min-height: 32px; font-size: .86rem; }
.linha-progresso .acoes { flex: none; }

/* 44px no rodapé do artigo: ali são controles ISOLADOS, não passageiros de um
   cartão tocável — merecem o alvo cheio que o núcleo manda dar. É a mesma
   forma da lista num tamanho diferente, que é exatamente o que "mesma
   identidade visual" quer dizer: a diferença é de contexto, não de desenho. */
.artigo > footer .acoes .redondo { width: 44px; height: 44px; font-size: 1.05rem; }

/* Aceso = o estado em que o artigo está. O segundo toque no aceso devolve à
   inbox — o `title` e o `aria-label` já dizem isso, e o fundo tingido é o que
   distingue "onde estou" de "para onde posso ir" sem precisar ler nada.

   O tingido não é a única pista (a cor da tinta e a da borda mudam junto), o
   que o dispensa de piso de contraste próprio — mesma razão registrada em
   `--perigo` para o fundo de `.armado`. */
/* Aceso, sobre o campo grafite: a tinta e a borda vão para o acento do cromo e
   o leito ganha uma lavagem dele. O `color-mix` é sobre o gradiente, então o
   campo continua sendo o mesmo material — só tingido. */
.acao-estado[aria-pressed="true"] {
  color: var(--cromo-acento); border-color: var(--cromo-acento);
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--cromo-acento) 20%, var(--cromo-1)),
    color-mix(in srgb, var(--cromo-acento) 20%, var(--cromo-2)));
}

/* O painel de diagnóstico não pode cobrir o que se está diagnosticando —
   foi o que aconteceu: ele tapou justamente o botão em teste. */
body:has(#diag) main { padding-bottom: 46vh; }

/* O ✕ é destrutivo, então pede o segundo toque. Mas **não muda de largura** ao
   ser armado: um botão que cresce empurra o que está ao lado, e o segundo
   toque cairia noutro lugar. Quem explica é a linha de aviso abaixo. */
/* `--cromo-perigo`, e não `--perigo`: o vermelho do papel claro é `#b81028`,
   uma tinta escolhida para ser lida sobre folha branca — sobre o campo grafite
   ele é escuro sobre escuro. Mesmo movimento que `--cromo-acento` fez em
   02/09, e pela mesma razão: o cromo não muda por tema, então quem escreve
   sobre ele também não. */
.redondo.excluir:hover, .redondo.excluir:focus-visible {
  color: var(--cromo-perigo); border-color: var(--cromo-perigo);
}
.redondo.excluir.armado {
  color: var(--cromo-perigo); border-color: var(--cromo-perigo);
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--cromo-perigo) 20%, var(--cromo-1)),
    color-mix(in srgb, var(--cromo-perigo) 20%, var(--cromo-2)));
}

/* O `<audio>` perdeu os `controls` em 07/09 e virou só o motor: quem aparece é
   `.transporte`, logo abaixo. A largura continua declarada porque o elemento
   sem `controls` tem caixa zero e `[hidden]` é o sinal que o JS lê — deixá-lo
   participar do fluxo com altura nenhuma evita um reflow ao revelar. */
.audio-leitura { width: 100%; height: 0; }
.audio-leitura[hidden] { display: none; }

/* ── O transporte do LIVRO  (07/09) ─────────────────────────────────────────

   Uma fileira só: passo, play, passo, relógio, barra, relógio. Os controles
   herdam o vocabulário do `.controles-voz` de propósito — os dois vivem
   colados no cabeçalho, e um `range` desenhado de outro jeito a dois
   centímetros do outro leria como dois apps.

   `display: none` no `[hidden]`, como em toda regra de autor com `display`
   aqui: `flex` vence o `[hidden]{display:none}` da folha do navegador, e sem
   esta linha o transporte apareceria antes de o leitor pedir a voz. */
.transporte { display: flex; align-items: center; flex-wrap: wrap; gap: .45rem; margin-top: .8rem; }
.transporte[hidden] { display: none; }

/* `min-width` e não `width`: o alvo mínimo é piso, e `−15`/`+15` são três
   caracteres que num quadrado de `--alvo` cru sairiam apertados. */
.transporte-botao {
  flex: none; min-width: var(--alvo); height: var(--alvo); padding: 0 .5rem;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--sans); font-size: .82rem; line-height: 1;
  color: var(--tinta); background: var(--papel-elev);
  border: 1px solid var(--borda-controle); border-radius: var(--raio-p);
  cursor: pointer;
}
.transporte-botao:hover, .transporte-botao:focus-visible { border-color: var(--acento); color: var(--acento); }
.transporte-play { font-size: 1rem; }
.transporte-airplay { color: var(--tinta-2); }

/* `tabular-nums` e largura mínima: sem elas a barra encolhe e cresce a cada
   segundo, e o dedo que ia pegar o polegar erra o alvo que acabou de andar.
   `5.4ch` cabe `11:34:27`, que é o maior relógio do acervo. */
.transporte-relogio {
  flex: none; min-width: 5.4ch; text-align: center;
  font-family: var(--sans); font-size: .76rem; font-variant-numeric: tabular-nums;
  color: var(--tinta-2);
}

/* A parte só aparece quando não há régua — e aí ela é a única verdade que o
   transporte tem para dar. */
.transporte-parte {
  flex: none; font-family: var(--sans); font-size: .68rem;
  letter-spacing: .04em; color: var(--tenue);
}
.transporte-parte[hidden] { display: none; }

/* A barra. Mesmo desenho do deslizante de velocidade — inclusive o
   `box-sizing` explícito no polegar, que o reset universal não alcança porque
   `::-webkit-slider-thumb` é pseudo-elemento do navegador.

   O que ela tem a mais é o PREENCHIMENTO à esquerda do polegar: numa barra de
   progresso é por ele que se lê «onde estou» de relance, e o trilho de cor
   única obrigaria a procurar o polegar. `--pct` é escrito pelo JS a cada
   pintura; o `0%` de partida existe para a barra nascer vazia e não herdar
   o valor da última que passou por aqui. */
.transporte-barra {
  --pct: 0%;
  flex: 1 1 12rem; min-width: 0; height: var(--alvo);
  -webkit-appearance: none; appearance: none;
  background: none; margin: 0; cursor: pointer;
}
.transporte-barra::-webkit-slider-runnable-track {
  height: 4px; border-radius: 2px;
  background: linear-gradient(to right, var(--acento) var(--pct), var(--borda-controle) var(--pct));
}
.transporte-barra::-moz-range-track {
  height: 4px; border-radius: 2px;
  background: linear-gradient(to right, var(--acento) var(--pct), var(--borda-controle) var(--pct));
}
.transporte-barra::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; box-sizing: border-box;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--acento); border: 2px solid var(--papel-elev);
  margin-top: -11px;
}
.transporte-barra::-moz-range-thumb {
  box-sizing: border-box;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--acento); border: 2px solid var(--papel-elev);
}
.transporte-barra:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* ── Os controles do player: velocidade e granularidade  (L-120) ────────────

   Nasceram sem uma linha de CSS. Funcionavam — `step="0.1"` sempre deu 0,8× —
   mas o deslizante era o nativo cru, ~130px de trilho para a faixa de 0,5 a
   2,0. São ~9px por parada para um dedo de ~40px de contato: o valor existia e
   não se conseguia apontar para ele. O que este bloco conserta é MIRA, não
   alcance.

   `display: none` no `[hidden]` é obrigatório, não zelo: `display: flex` numa
   regra de autor vence o `[hidden]{display:none}` da folha do navegador, e sem
   esta linha os controles apareceriam ANTES de o leitor pedir a voz — que é a
   coisa exata que o comentário do markup diz não querer. Mesma armadilha que
   `.audio-leitura[hidden]` acima já resolvia. */
/* ── Duas filas, e a divisão é por NATUREZA do ato  (12/09) ─────────────────

   Antes era uma fila só em `flex-wrap`, com a ordem de chegada: velocidade,
   destaque, voz. Abaixo de ~380px ela quebrava em três alturas desiguais e o
   seletor de voz — o único controle que decide QUEM fala, e do qual pende um
   gasto de verdade — descia para o fim, atrás dos dois que só ajustam COMO se
   fala.

   `grid` com duas filas separa a AÇÃO (qual motor; gerar o do estúdio) do
   AJUSTE (velocidade; destaque). Cada fila quebra dentro de si, e nenhuma
   consegue se embaralhar com a outra por falta de largura. */
.controles-voz { display: grid; gap: .85rem; margin-top: .9rem; }
.controles-voz[hidden] { display: none; }
.controles-voz .fila-voz { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .9rem 1.4rem; }
/* A mesma armadilha do `[hidden]` que a barra inteira já resolvia, agora uma
   camada abaixo: `display: flex` numa regra de autor vence o `[hidden]` da
   folha do navegador, e a fila do ajuste vazaria para antes da escuta. */
.controles-voz .fila-voz[hidden] { display: none; }
/* ── A fila da ação: dois controles que sentam na MESMA linha  (12/09) ──────

   `align-items: center` centrava os dois BLOCOS, e os blocos não são iguais: o
   do motor carrega a sobrancelha «Voz» por cima do segmentado, o de gerar é um
   botão pelado. Centrar um bloco alto contra um baixo põe o botão acima do
   segmentado — o desalinho de 6px que se vê antes de se saber explicar.

   `flex-end` casa as bases, e a conta abaixo iguala as alturas: a pílula mede o
   alvo de toque por dentro, e o quadro do segmentado a envolve com a folga dos
   dois lados mais as duas bordas. O botão de gerar usa a MESMA conta — não um
   `50px` copiado, que envelheceria calado no dia em que `--alvo` mudasse. */
.controles-voz .fila-voz.acao { --folga-seg: 2px; align-items: flex-end; }

/* A velocidade toma a linha e a granularidade cabe ao lado quando há espaço;
   `16rem` é a base a partir da qual o deslizante ainda tem trilho útil — abaixo
   disso a fileira quebra em vez de espremer. */
.controles-voz .velocidade { flex: 1 1 16rem; min-width: 0; }

/* Mesma sobrancelha do painel de ajustes e da lista: o rótulo em cima, não ao
   lado, porque ao lado ele come a largura que o trilho precisa ter. */
.controles-voz .rotulo {
  display: block; font-family: var(--sans); font-size: .62rem; font-weight: 600;
  letter-spacing: .09em; text-transform: uppercase; color: var(--tenue);
  margin: 0 0 .4rem .1rem;
}
.controles-voz .estepe { display: flex; align-items: center; gap: .5rem; }

/* Os dois botões de passo. Quadrado de `--alvo` cheio: o ponto deste controle
   é ser acertável, e um botão de passo menor que o alvo mínimo devolveria o
   problema que ele veio resolver. `line-height: 1` porque o `−` e o `+` são
   glifos altos e o padding sozinho os desalinharia do centro. */
.controles-voz .passo-voz {
  flex: none; width: var(--alvo); height: var(--alvo);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--sans); font-size: 1.05rem; line-height: 1;
  color: var(--tinta); background: var(--papel-elev);
  border: 1px solid var(--borda-controle); border-radius: var(--raio-p);
  cursor: pointer;
}
.controles-voz .passo-voz:hover:not([disabled]),
.controles-voz .passo-voz:focus-visible { border-color: var(--acento); color: var(--acento); }
/* No extremo da faixa. `.5` e não `.4`: é a mesma opacidade de `.btn[disabled]`,
   e os dois controles convivem na mesma tela. */
.controles-voz .passo-voz[disabled] { opacity: .5; cursor: default; }

/* O valor. `tabular-nums` para a fileira não dançar quando 1,0× vira 0,9×, e
   largura mínima pelo mesmo motivo — sem ela o `+` anda para o lado a cada
   passo, e o dedo que ia clicar de novo erra o botão que acabou de mover. */
.controles-voz .valor {
  flex: none; min-width: 3.2ch; text-align: right;
  font-family: var(--sans); font-size: .85rem; font-variant-numeric: tabular-nums;
  color: var(--tinta);
}

/* O deslizante. `appearance: none` obriga a desenhar trilho e polegar à mão nos
   dois motores — e a altura de `--alvo` não é a espessura do trilho (4px), é a
   ÁREA DE TOQUE: o trilho fino fica no meio de uma faixa alta o bastante para
   o dedo. */
.controles-voz input[type="range"] {
  flex: 1 1 auto; min-width: 0; height: var(--alvo);
  -webkit-appearance: none; appearance: none;
  background: none; margin: 0; cursor: pointer;
}
.controles-voz input[type="range"]::-webkit-slider-runnable-track {
  height: 4px; border-radius: 2px; background: var(--borda-controle);
}
.controles-voz input[type="range"]::-moz-range-track {
  height: 4px; border-radius: 2px; background: var(--borda-controle);
}
/* O WebKit não centra polegar em trilho por conta própria: a margem negativa
   tem de ser escrita, e ela é (altura do trilho − caixa do polegar) / 2 —
   (4 − 26) / 2 = −11px.

   `box-sizing` explícito, e não herdado do reset: o `*,*::before,*::after` do
   núcleo NÃO alcança `::-webkit-slider-thumb`, que é pseudo-elemento do
   navegador e não casa com o universal. Sem esta linha a caixa seria 26 + 2×2
   = 30px em vez de 26px, a margem certa passaria a ser −13px, e o polegar
   ficaria 2px fora do eixo do trilho — desalinho pequeno demais para se ver
   no Mac e visível no iPad, que é onde este controle é usado. Declarar a
   regra torna a conta decidível em vez de dependente do motor.

   O anel em `--papel-elev` é o que separa o polegar do trilho quando os dois
   passam por cima da mesma cor. */
.controles-voz input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; box-sizing: border-box;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--acento); border: 2px solid var(--papel-elev);
  margin-top: -11px;
}
.controles-voz input[type="range"]::-moz-range-thumb {
  box-sizing: border-box;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--acento); border: 2px solid var(--papel-elev);
}
.controles-voz input[type="range"]:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* A granularidade: rótulo em cima como o da velocidade, e o `<select>` com a
   mesma altura de alvo dos botões de passo — os dois controles são uma fileira
   só aos olhos, e alturas diferentes a fariam parecer duas. */
.controles-voz .granularidade,
.controles-voz .timbre { flex: 0 1 auto; display: block; min-width: 0; }
.controles-voz .granularidade > span,
.controles-voz .timbre > span {
  display: block; font-family: var(--sans); font-size: .62rem; font-weight: 600;
  letter-spacing: .09em; text-transform: uppercase; color: var(--tenue);
  margin: 0 0 .4rem .1rem;
}
/* `height`, e não só `min-height`: o `<select>` nativo ignora o mínimo e desenha
   na altura da própria fonte, e a fileira do ajuste ficava com dois controles de
   alturas diferentes — as duas sobrancelhas (VELOCIDADE e DESTAQUE) pousavam em
   linhas distintas, que é o desalinho que se vê antes de se saber explicar. */
.controles-voz .granularidade select,
.controles-voz .timbre select {
  height: var(--alvo); font-family: var(--sans); font-size: .82rem;
  color: var(--tinta); background: var(--papel-elev);
  border: 1px solid var(--borda-controle); border-radius: var(--raio-p);
  padding: 0 .6rem; cursor: pointer;
}
.controles-voz .granularidade[hidden],
.controles-voz .timbre[hidden] { display: none; }
/* O seletor de voz carrega nomes longos («Automática · Karen (Premium) ·
   Austrália»): sem teto, empurraria a oficina do estúdio para fora da fila no
   iPhone. Encolhe até o teto e corta com reticências — o menu aberto mostra o
   nome inteiro. */
.controles-voz .timbre select { max-width: min(22rem, 100%); text-overflow: ellipsis; }
/* Na fila da AÇÃO ele pousa ao lado do segmentado do motor, que tem o alvo
   MAIS a folga das pílulas e a borda do campo (2 + 2 + 1 + 1). Com a altura do
   alvo só, as duas sobrancelhas (VOZ e QUEM LÊ) ficavam 6px desencontradas —
   o mesmo desalinho que a granularidade já tinha resolvido na fila de baixo. */
.controles-voz .acao .timbre select { height: calc(var(--alvo) + 2 * var(--folga-seg, 2px) + 2px); }

/* ── O motor da voz: segmentado, não `<select>`  (12/09) ────────────────────

   Com DOIS valores, o menu suspenso esconde metade do controle: a alternativa
   só existe depois de um toque que não escolhe nada. O segmentado mostra as
   duas o tempo todo, a vigente acesa, e a troca custa o toque que antes só
   servia para abrir o menu.

   A caixa externa é o campo; as pílulas vivem DENTRO dela, com 2px de folga —
   é essa folga que faz a acesa parecer encaixada em vez de colada. O raio de
   dentro é o de fora menos a folga, senão o canto da pílula acesa corta o
   canto do campo. */
.controles-voz .motor-voz { flex: 0 0 auto; }
.controles-voz .motor-voz .segmentado {
  display: inline-flex; padding: var(--folga-seg, 2px); gap: 2px;
  background: var(--papel-elev);
  border: 1px solid var(--borda-controle);
  border-radius: var(--raio-p);
}
.controles-voz .motor-voz .opcao {
  min-height: var(--alvo); padding: 0 .9rem;
  font-family: var(--sans); font-size: .82rem; line-height: 1;
  color: var(--tinta-2); background: none; border: 0;
  border-radius: calc(var(--raio-p) - 2px);
  cursor: pointer; white-space: nowrap;
}
/* Acento cheio com `--sobre-acento`, nunca `#fff`: no tema escuro o acento é
   claro, e um branco cravado ali cairia para ~2:1 sobre ele. */
.controles-voz .motor-voz .opcao[aria-checked="true"] {
  background: var(--acento); color: var(--sobre-acento);
}
/* Apagada, não ausente: a opção indisponível ainda ensina que a segunda voz
   existe — é a oficina, logo ao lado, que a destrava. */
/* `.5`, o mesmo dos botões de passo apagados: é o número que esta barra já usa
   para «existe e não dá para acionar», e dois números para o mesmo estado são
   duas linguagens na mesma fileira. */
.controles-voz .motor-voz .opcao[data-indisponivel="sim"] { opacity: .5; }
.controles-voz .motor-voz .opcao:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* ── O botão que custa, e a conta antes dele ────────────────────────────────

   O botão é secundário de propósito (borda, não acento cheio): o primário
   desta tela é ouvir, e ouvir já é de graça. Quem gasta é este, e ele não
   convida — ele espera.

   A altura é a EXTERNA do segmentado ao lado, derivada dele: alvo de toque por
   dentro, mais a folga dos dois lados, mais as duas bordas. */
.controles-voz .gerar-estudio {
  min-height: calc(var(--alvo) + 2 * var(--folga-seg, 2px) + 2px); padding: 0 .9rem;
  font-family: var(--sans); font-size: .82rem;
  color: var(--tinta); background: none;
  border: 1px solid var(--borda-controle); border-radius: var(--raio-p);
  cursor: pointer;
}
.controles-voz .gerar-estudio:hover,
.controles-voz .gerar-estudio:focus-visible { border-color: var(--acento); color: var(--acento); }
.controles-voz .gerar-estudio[hidden] { display: none; }

/* ── A narração de uma régua anterior  (spec 58 §4) ─────────────────────────

   Aviso, não alarme: o que está tocando é legítimo e foi pago; só não é da
   régua de hoje. Por isso a tinta fraca da nota de rodapé, e não a do erro —
   quem sobe a régua quer saber, quem só quer ouvir não precisa ser
   interrompido. `Regravar` é link de texto pela mesma razão: ele custa uma
   síntese inteira, e um botão sólido convidaria a gastar. */
.controles-voz .regua-anterior {
  margin: .45rem 0 0; font-family: var(--sans); font-size: .78rem;
  color: var(--tinta-2); line-height: 1.5;
}
.controles-voz .regua-anterior[hidden] { display: none; }
.controles-voz .regua-anterior .btn.discreto {
  min-height: var(--alvo); padding: 0 .35rem;
  font: inherit; color: var(--acento); background: none; border: 0;
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer;
}
.controles-voz .regua-anterior .btn.discreto:focus-visible {
  outline: 2px solid var(--foco); outline-offset: 2px;
}

/* A conta do gasto saiu daqui na spec 53 (16/09): a caixa embutida
   (`.confirma-estudio`, com a conta em caracteres) virou a folha do
   `confirmarComCusto` — `.custo-fundo`, mais abaixo neste arquivo —, e a
   pele dela ficou órfã até 17/09. Regra que não casa com elemento nenhum não
   avisa: ela só engorda a folha e finge que o mecanismo ainda existe. */

.aviso-excluir {
  font-family: var(--sans); font-size: .76rem; color: var(--perigo);
  margin: .5rem 0 0; padding-left: .1rem;
}
/* A falha de rede ao mudar de estado fala no mesmo lugar e no mesmo tom que a
   confirmação do ✕ — é uma linha abaixo do item, não um alerta que rouba a
   tela. Em --tinta-2 e não em --perigo: nada se perdeu, só não foi feito. */
.aviso-estado {
  font-family: var(--sans); font-size: .76rem; color: var(--tinta-2);
  margin: .5rem 0 0; padding-left: .1rem;
}

/* ── O sinal da voz de estúdio  (spec 11 §6, revisto em 14/09) ─────────────
   Três barras de onda, e nenhum aro: o aro era a forma do BOTÃO da casa, e
   este sinal não é botão — da lista e da estante só se vê que a narração
   existe; gerá-la passa pela conta, dentro do artigo (spec 49 §4.2). A cor é
   `currentColor` para servir nas duas superfícies: acento sobre o papel da
   lista, a tinta da lombada sobre o campo escuro da estante. Gerando é o mesmo
   desenho, pulsando. Ver `montarSinalEstudio` em inbox.mjs. */
.sinal-estudio {
  display: inline-flex; align-items: center; gap: .4rem;
  color: var(--acento); cursor: default; line-height: 1;
}
.sinal-estudio svg { flex: none; fill: currentColor; }
.sinal-estudio.gerando { animation: sinal-pulso 1.4s ease-in-out infinite; }
@keyframes sinal-pulso { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
/* Sem animação, gerando seria idêntico a pronta — o tom apagado é o que resta
   de pista quando o movimento é vetado. */
@media (prefers-reduced-motion: reduce) {
  .sinal-estudio.gerando { animation: none; opacity: .55; }
}
.item .progresso.vazia { flex: 1; background: none; }

/* "Temas" antes dos chips: sem o rótulo, a fileira logo abaixo das abas parece
   um segundo filtro do mesmo recorte — e a contagem, que é do tema e não da
   aba, passa a parecer errada. */
.clusters .rotulo-temas {
  display: block; color: var(--tenue); font-size: .68rem; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; margin: 0 0 .45rem .1rem;
}

/* ── administração (spec 19) ────────────────────────────────────────────────
   Formulário de operação, não tela de leitura: tudo em --sans, painéis na
   mesma gramática dos cartões da inbox (borda --borda-controle, fundo
   --papel-elev) e controles nativos — select e input herdam o tema em vez de
   fingir outro sistema. O link do rodapé vive na regra do #versao. */
#versao a { color: inherit; text-decoration: none; }
#versao a:hover, #versao a:focus-visible { color: var(--acento); }

#admin { font-family: var(--sans); }
#admin > .sub { margin: -.2rem 0 1.1rem; color: var(--tinta-2); font-size: .88rem; }
#admin .painel {
  background: var(--papel-elev); border: 1px solid var(--borda-controle);
  border-radius: 10px; padding: 1rem 1.1rem; margin: 0 0 1.1rem;
}
#admin .painel h2 { font-size: .95rem; font-weight: 600; margin: 0 0 .6rem; }
#admin .painel .sub { margin: -.3rem 0 .9rem; line-height: 1.5; font-size: .82rem;
  color: var(--tinta-2); }
#admin .estado { margin: 0; display: grid; gap: .8rem 1.4rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }
#admin .estado dt { font-size: .72rem; color: var(--tenue); letter-spacing: .04em;
  text-transform: uppercase; }
#admin .estado dd { margin: .1rem 0 0; font-size: .88rem;
  font-variant-numeric: tabular-nums; }
#admin .estado dd.mini { font-size: .72rem; color: var(--tenue); }

/* ── A gramática única (14/09) ──────────────────────────────────────────────
   Um bloco por papel de IA — título, o que governa, e as caixas lado a lado —
   e toda caixa da página com a mesma forma: rótulo, marca «alterado» quando o
   valor salvo não é o padrão, a caixa, e a nota que explica por que ela está
   desligada. O `fieldset` é o agrupamento que o leitor de tela anuncia; a
   `legend` flutua porque é o único jeito de ela ocupar a largura sem o
   desenho de moldura que o navegador lhe dá. */
#admin .papel { border: 0; border-top: 1px solid var(--borda-controle);
  margin: 0; padding: .95rem 0 .15rem; min-width: 0; }
#admin .papel:first-of-type { border-top: 0; padding-top: .1rem; }
#admin .papel legend { float: left; width: 100%; padding: 0; margin: 0 0 .15rem;
  font-size: .9rem; font-weight: 600; }
#admin .papel .governa { clear: both; margin: 0 0 .65rem; font-size: .8rem;
  line-height: 1.45; color: var(--tinta-2); }
#admin .grade-campos { display: grid; column-gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); }
/* No bloco de papel o MODELO é a caixa larga: o rótulo dele carrega id,
   provedor, preço e «(padrão)», e em meia coluna saía cortado no meio do
   preço («US$ 5/25 (pad…»). O esforço e o liga/desliga cabem em pouco. */
@media (min-width: 700px) {
  #admin .papel .grade-campos { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
  #admin .papel .grade-campos:has(#vozIa) { grid-template-columns: minmax(0, 1fr) minmax(0, 2.4fr) minmax(0, 1fr); }
}
#admin .campo { display: block; margin: 0 0 .8rem; min-width: 0; }
#admin .campo > label { display: flex; align-items: baseline; flex-wrap: wrap; gap: .45rem;
  font-size: .76rem; font-weight: 600; margin: 0 0 .3rem; }
#admin .alterado { font-size: .64rem; font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; color: var(--acento); border: 1px solid currentColor;
  border-radius: 999px; padding: 0 .4rem; line-height: 1.5; }
#admin .campo select, #admin .campo textarea {
  width: 100%; box-sizing: border-box; font: inherit; font-size: .88rem;
  color: var(--tinta); background: var(--papel); border: 1px solid var(--borda-controle);
  border-radius: 7px; padding: .5rem .6rem; min-height: 44px;
}
/* O Safari desenha o `<select>` nativo com a altura dele e IGNORA `min-height`
   e `padding` — medido: 22px, metade do alvo de toque. `appearance: none`
   devolve a caixa ao CSS, e a seta passa a ser desenhada aqui, com dois
   gradientes na tinta tênue do tema (um SVG em `url()` não herdaria a cor). */
#admin .campo select {
  -webkit-appearance: none; appearance: none; padding-right: 2.1rem;
  background-image: linear-gradient(45deg, transparent 50%, var(--tenue) 50%),
    linear-gradient(135deg, var(--tenue) 50%, transparent 50%);
  background-position: calc(100% - 1.05rem) 50%, calc(100% - .75rem) 50%;
  background-size: .3rem .3rem; background-repeat: no-repeat;
  text-overflow: ellipsis;
}
#admin .campo select:focus-visible, #admin .campo textarea:focus-visible {
  outline: none; border-color: var(--acento);
}
#admin .campo select:disabled { opacity: .5; cursor: not-allowed; }
/* O campo com escolha ainda não salva: um fio de acento na borda esquerda, o
   mesmo sinal que a barra de salvar lista por extenso. */
#admin .campo[data-pendente] select, #admin .campo[data-pendente] textarea {
  border-color: var(--acento); box-shadow: inset 3px 0 0 var(--acento);
}
#admin .campo .nota { display: block; font-size: .72rem; line-height: 1.4;
  color: var(--tenue); margin-top: .3rem; }
#admin .campo .erro-campo { display: block; font-size: .76rem; font-weight: 600;
  line-height: 1.4; color: var(--acento); margin-top: .35rem; }
/* Os hosts da bancada (spec 42 §3.5): um por linha, em mono — é lista, não
   prosa, e `resize: vertical` porque a largura é a do painel. */
#admin .campo textarea { font-family: var(--mono); line-height: 1.5;
  resize: vertical; }
#admin .painel h3 { font-size: .82rem; font-weight: 600; margin: 1rem 0 .4rem; }
#admin .fontes-admin { list-style: none; margin: 0; padding: 0; font-size: .85rem; }
#admin .fontes-admin li { padding: .5rem 0; border-top: 1px solid var(--borda-controle);
  line-height: 1.5; }
#admin .fontes-admin small { color: var(--tenue); font-size: .75rem; }
#admin .fontes-admin small.motivo { color: var(--tinta-2); }
#admin .fontes-admin code { font-size: .8rem; }
#admin .fontes-admin [data-estado="pendente"] .estado-fonte { color: var(--acento); font-weight: 600; }
#admin .fontes-admin [data-estado="recusada"] .estado-fonte,
#admin .fontes-admin [data-estado="falhou"] .estado-fonte { color: var(--tinta-2); }
/* As sessões da bancada (spec 43 §5). Mesma forma da lista das fontes — é a
   mesma pergunta, «o que o servidor tem sobre isto» — com duas diferenças:
   esta lista TEM botão, e o total do mês vem antes dela, porque é o número que
   se veio conferir antes de escolher o teto logo acima. */
#admin .total-sessoes { margin: 0 0 .3rem; font-size: .8rem; color: var(--tinta-2); }
#admin .sessoes-admin { list-style: none; margin: 0; padding: 0; font-size: .85rem; }
#admin .sessoes-admin li { padding: .5rem 0; border-top: 1px solid var(--borda-controle);
  line-height: 1.5; }
#admin .sessoes-admin small { color: var(--tenue); font-size: .75rem; }
#admin .sessoes-admin [data-viva] b { color: var(--acento); }
#admin .linha-sessao { display: flex; align-items: flex-start; justify-content: space-between;
  gap: .8rem; }
#admin .btn.encerrar { flex: none; font-size: .78rem; padding: .35rem .8rem; }
#admin #sessoes-status { display: block; font-size: .8rem; color: var(--tinta-2);
  margin-top: .5rem; }
#admin #sessoes-status:empty { display: none; }
/* O custo da memória por obra (17/09). Não tinha regra nenhuma: `ul` e `b`
   herdavam o corpo da leitura, e sete livros viravam uma página de prosa em
   negrito. Mesma forma das sessões — total antes, título e dólar numa linha. */
#admin .total-custos { margin: 1rem 0 .3rem; font-size: .8rem; color: var(--tinta-2); }
#admin .custos-memoria { list-style: none; margin: 0; padding: 0; font-size: .85rem; }
#admin .custos-memoria li { padding: .5rem 0; border-top: 1px solid var(--borda-controle);
  line-height: 1.5; }
#admin .custos-memoria b { font-weight: 600; }
#admin .custos-memoria small { display: block; color: var(--tenue); font-size: .75rem; }
#admin .linha-custo { display: flex; align-items: baseline; justify-content: space-between;
  gap: .8rem; }
#admin .linha-custo .usd { flex: none; font-variant-numeric: tabular-nums; color: var(--tinta-2); }

/* ── A barra de salvar ──────────────────────────────────────────────────────
   Presa ao pé da janela enquanto se rola, porque o que ela diz — quantas
   escolhas estão por salvar, e quais — é a pergunta de antes de sair da
   página. `--barra-h` é a altura da navegação inferior no iPad e no telefone
   (zero no modo lateral): sem ela a barra pousaria debaixo dos ícones. */
#admin .barra-salvar {
  position: sticky; bottom: calc(var(--barra-h, 0px) + .6rem); z-index: 5;
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .4rem 1rem; align-items: center;
  background: var(--papel-elev); border: 1px solid var(--borda-controle); border-radius: 10px;
  padding: .7rem .9rem; margin: 1.2rem 0 0; box-shadow: 0 4px 18px rgb(0 0 0 / .14);
}
#admin .barra-salvar:has(#pendencias li) { border-color: var(--acento); }
#admin #pendencias p { margin: 0; font-size: .82rem; }
#admin #pendencias .nada { color: var(--tenue); }
#admin #pendencias .conta { font-weight: 600; }
#admin #pendencias ul { margin: .25rem 0 0; padding-left: 1rem; font-size: .78rem;
  line-height: 1.45; color: var(--tinta-2); max-height: 7.5rem; overflow: auto;
  overflow-wrap: anywhere; }
#admin .barra-salvar .botoes { display: flex; gap: .5rem; }
#admin .barra-salvar .btn { min-height: 44px; padding: .5rem 1.1rem; font-size: .88rem; }
#admin #admin-status { grid-column: 1 / -1; font-size: .8rem; color: var(--tinta-2); }
#admin #admin-status:empty { display: none; }
@media (max-width: 560px) {
  #admin .barra-salvar { grid-template-columns: 1fr; }
  #admin .barra-salvar .botoes { justify-content: flex-end; }
}

/* ── A estante  (spec 21 §3.3) ─────────────────────────────────────────────
   A grade de capas. Duas regras aqui não são estética e sim defeito conhecido:
   a proporção fixa (sem ela a fileira desalinha e a grade deixa de parecer
   estante) e o título FORA da imagem — texto dentro de imagem gerada é onde a
   IA erra feio, e o nosso já está em Literata de graça.

   `auto-fill` em vez de contagem fixa de colunas porque o iPad girando é o
   caso comum: um `repeat(4, 1fr)` desperdiça meia tela em paisagem e aperta
   em retrato. */
.titulo-tela { font-family: var(--serif); font-size: 1.3rem; margin: 0 0 1rem; font-weight: 600; }

/* ── A estante VIVA: prateleiras à esquerda, capa à direita  (02/09) ───────
   A grade de capas em campo cheio saiu. Ela tinha um defeito que a rodada
   inteira existe para desfazer: a única superfície de cor forte do app era
   justamente a tela que devia ser a mais discreta — vinte e seis capas
   saturadas lado a lado.

   O que entra é a LOMBADA de pé numa prateleira, e a capa vira detalhe de
   foco: uma por tela, na coluna da direita. É a inversão que faz a estante
   parecer estante — numa de verdade se veem lombadas, e a capa só aparece
   quando se tira o livro.

   A coluna some abaixo de 900px: no iPhone ela comeria metade da tela para
   mostrar um livro de cada vez, e a prateleira inteira caberia em nada. */
.estante-viva { display: flex; align-items: flex-start; gap: 2rem; }
.estante-viva .prateleiras { flex: 1; min-width: 0; }

.prateleira { margin: 0 0 2rem; }
.prateleira h2 {
  font-family: var(--sans); font-size: 10.5px; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--tinta-2); margin: 0 0 .7rem;
  display: flex; align-items: center; gap: .5rem;
}
/* A pílula da contagem em aro fino: ela conta, não comanda — e o piso de 3:1
   é de borda que é a única pista de CONTROLE. */
.prateleira h2 .conta {
  font-size: 10.5px; color: var(--tenue); background: none;
  border: 1px solid var(--aro-fino); border-radius: 999px; padding: 2px 7px;
  font-variant-numeric: tabular-nums;
}

/* ── A prateleira ROLA  (prancha 1e, 2026-09-01) ───────────────────────────
   «A prateleira não é uma grade com título: a fileira rola na horizontal e o
   corte à direita é a pista de que há mais.»

   A grade de `auto-fill` que morava aqui resolvia bem o iPad girando, e é por
   isso que ela durou — mas ela mente sobre o objeto: uma grade que quebra em
   três linhas diz «este é o conjunto todo», e uma estante nunca mostra o
   conjunto todo. O corte é a informação.

   `scroll-snap` no eixo X para o dedo parar em capa inteira, e `overscroll-
   behavior-x: contain` para a rolagem da fileira não virar rolagem da página
   quando ela chega ao fim — no iPad, sem isso, arrastar a última capa arrasta
   a tela. A classe mudou de `.grade` para `.fileira`: o nome antigo descrevia
   a diagramação que saiu, e `#ajustes .grade` continua existindo. */
/* A fileira alinha as lombadas pela BASE — elas têm alturas diferentes, e o
   que as iguala numa estante é a tábua, não o topo.

   A altura da fileira é ~24px maior que a lombada mais alta, e isso não é
   folga solta: é o que o `translateY(-14px)` do hover consome. Sem ela o livro
   sobe por cima do rótulo da prateleira. */
/* A fileira alinha as lombadas pela BASE de cada LINHA — em flex com quebra o
   alinhamento cruzado é por linha, e é isso que põe cada livro sobre a sua
   tábua. `align-content: flex-start` impede as linhas de se espalharem na
   altura que sobrar.

   ── A tábua de cada linha é DESENHADA NO FUNDO, e por quê ─────────────────
   Um `<span class="tabua">` por linha é impossível: quem decide onde a linha
   quebra é o navegador, com a largura da tela e as larguras variáveis das
   lombadas — o HTML não sabe quantas linhas existem. Um `repeating-linear-
   gradient` sabe: as lombadas de uma prateleira têm todas a MESMA altura e o
   `row-gap` é fixo, então o passo é exato e o desenho acompanha qualquer
   número de linhas, em qualquer largura, sem uma linha de JavaScript.

   A folga do hover (`translateY(-14px)`) é MARGEM, e não padding: o fundo
   pinta a caixa de padding, e 16px de padding-top deslocariam o gradiente
   inteiro meio degrau para baixo — a tábua sairia atravessando os livros. */
.prateleira .fileira {
  list-style: none; margin: 16px 0 0;
  /* O padding de baixo é o que faz a tábua da ÚLTIMA linha existir: o fundo
     pinta a caixa de padding, e sem esses 31px a caixa termina exatamente onde
     a lombada termina — a faixa de madeira ficaria fora dela. Foi o que a
     captura mostrou na prateleira «Lendo agora», que tem uma linha só. */
  padding: 0 0 31px;
  display: flex; flex-wrap: wrap;
  align-items: flex-end; align-content: flex-start;
  column-gap: 5px;
  /* 31px = a tábua (9) mais o respiro até a linha de baixo (22). É o mesmo
     número que fecha o passo do gradiente. */
  row-gap: 31px;
  --lombada-h: 238px;
  --linha-h: calc(var(--lombada-h) + 31px);
  background-image: repeating-linear-gradient(to bottom,
    transparent 0 var(--lombada-h),
    /* o brilho de cima da madeira */
    rgba(255,255,255,.5) var(--lombada-h) calc(var(--lombada-h) + 1px),
    var(--tabua-1) calc(var(--lombada-h) + 1px),
    var(--tabua-2) calc(var(--lombada-h) + 9px),
    /* a sombra projetada, que o `box-shadow` de um elemento daria */
    rgba(34,33,29,.13) calc(var(--lombada-h) + 9px),
    transparent calc(var(--lombada-h) + 20px) var(--linha-h));
}
/* As prateleiras que não são «Lendo agora» têm a lombada 14px mais baixa: é o
   que faz a fileira em curso se ler primeiro sem precisar de cor nem de peso
   de fonte. O gradiente acompanha porque o passo dele sai deste mesmo token. */
.prateleira:not([data-chave="lendo"]) .fileira { --lombada-h: 224px; }
.prateleira .fileira > .obra { flex: 0 0 auto; width: auto; height: auto; }

/* ── A LOMBADA ────────────────────────────────────────────────────────────
   Largura variável (36–68px, `--largura`, escrita pelo `estante.mjs` a partir
   da extensão da obra) e altura fixa por prateleira. O gradiente de 90° é o
   volume: uma luz na quina esquerda, sombra crescendo até a direita — é o que
   separa «lombada» de «retângulo colorido».

   O canto de FORA é o arredondado (`2px 4px 4px 2px`), como num livro fechado:
   a lombada dobra para a direita, onde estão as folhas. */
/* ── Duas heranças da vista GRADE que precisam ser desfeitas aqui ──────────
   `.obra .alvo` declara `flex: 1` para empurrar as ações para a base do cartão
   da grade. Num contêiner flex em COLUNA o `flex-basis: 0%` que vem junto
   vence o `height` — e a lombada nascia com a altura do texto: 124px numa
   obra, 171 na vizinha, na mesma fileira. `flex: none` devolve a altura
   declarada.

   O `.titulo` da grade é `-webkit-box` com `line-clamp: 2`, e um `-webkit-box`
   ignora `writing-mode` no WebKit: o título saía deitado dentro da lombada de
   pé. Ver a regra do título, adiante. */
.obra.lombada .alvo {
  display: flex; flex: none; flex-direction: column; align-items: center;
  width: var(--largura, 44px); height: 238px;
  padding: 12px 4px 14px; box-sizing: border-box;
  border-radius: 2px 4px 4px 2px;
  background:
    linear-gradient(90deg, rgba(255,255,255,.15), rgba(255,255,255,0) 15%,
                    rgba(0,0,0,.12) 74%, rgba(0,0,0,.3)),
    var(--lombada, var(--t-cheio, var(--tenue)));
  box-shadow: var(--sombra-lombada);
  color: var(--sobre-lombada);
  overflow: hidden; cursor: pointer;
  transition: transform var(--dur) var(--curva);
}
.prateleira:not([data-chave="lendo"]) .obra.lombada .alvo { height: 224px; }
/* Sobe ao passar E ao receber foco: hover é atalho, foco é interface. Um
   realce que só existe com o cursor em cima não existe para quem usa
   teclado. */
.obra.lombada .alvo:hover, .obra.lombada .alvo:focus-visible {
  transform: translateY(-14px);
}
@media (prefers-reduced-motion: reduce) {
  .obra.lombada .alvo { transition: none; }
}
/* O filete do topo: a linha de capa que quase toda coleção tem. Acompanha a
   largura da lombada em vez de ser fixo, senão numa de 68px ele vira um
   traço perdido no meio. */
.obra.lombada .filete {
  display: block; flex: none; height: 1px; width: 60%;
  background: rgba(255,255,255,.42); margin-bottom: 12px;
}
/* `vertical-rl` sem `rotate(180deg)`: o título lê de cima para baixo, que é a
   convenção das lombadas em português. O corte é por `overflow`, e o texto
   continua INTEIRO no DOM — é o que o leitor de tela ouve e o que a busca do
   navegador acha. */
/* ── O título da lombada é UMA linha, e corta com reticências  (02/09) ─────
   `overflow: hidden` sozinho não bastava: em `writing-mode: vertical-rl` o
   texto que não cabe **quebra em outra coluna**, e a coluna nova cresce para o
   lado — para dentro da lombada, por cima do que já estava escrito. «Carmilla
   (Clássicos da literatura mundial)» virava duas colunas sobrepostas numa
   lombada de 40px (relato do Yuri, com o app aberto).

   `white-space: nowrap` mantém tudo numa coluna só e devolve o corte ao eixo
   que a lombada controla — a altura —, e aí `text-overflow: ellipsis` diz onde
   ele acabou. O texto continua INTEIRO no DOM: é o que o leitor de tela ouve,
   o que a busca do navegador acha, e o que a coluna da capa mostra por
   extenso quando o livro recebe o foco. */
.obra.lombada .titulo {
  /* `block`, desfazendo o `-webkit-box` da vista grade: o box do WebKit ignora
     `writing-mode`, e o título ficava deitado numa lombada de pé. */
  display: block; -webkit-line-clamp: none; min-height: 0;
  writing-mode: vertical-rl; text-orientation: mixed;
  font-family: var(--serif); font-weight: 600; font-size: 13px; line-height: 1.15;
  max-height: 170px; overflow: hidden; text-align: left;
  white-space: nowrap; text-overflow: ellipsis;
}
.prateleira:not([data-chave="lendo"]) .obra.lombada .titulo {
  font-size: 12px; max-height: 158px;
}
.obra.lombada .autor {
  writing-mode: vertical-rl; text-orientation: mixed;
  font-family: var(--sans); font-weight: 600; font-size: 8px; letter-spacing: .16em;
  text-transform: uppercase; margin-top: auto;
  /* Mesma razão do título: o nome longo («Joseph Sheridan Le Fanu») abria uma
     segunda coluna que crescia por cima da lombada. */
  white-space: nowrap; text-overflow: ellipsis;
  /* 65%, e não os 60% do desenho: a 60% o pior par das cinco tintas (petróleo)
     media 4,67:1 — passava o piso de 4.5 e raspava a mira de 4.7 da casa.
     Texto miúdo não afrouxa piso por ser miúdo; ele sobe a opacidade. */
  color: color-mix(in srgb, var(--sobre-lombada) 65%, transparent);
  max-height: 90px; overflow: hidden;
}
/* No PÉ da lombada, onde a estante de verdade põe o sinete da editora. Na
   tinta da lombada, e não no acento: brasa sobre bordô some (ver o título).
   Sem autor, é ele quem desce ao pé. */
.obra.lombada .sinal-estudio {
  flex: none; margin-top: 10px; color: var(--sobre-lombada);
}
.obra.lombada .titulo + .sinal-estudio { margin-top: auto; }

/* ── A TÁBUA ──────────────────────────────────────────────────────────────
   Nove pixels de madeira vista de canto, com o brilho de cima e a sombra
   projetada logo abaixo. Sem ela as lombadas flutuam — e lombada que não se
   apoia em nada se lê como barra de gráfico, não como livro.

   Desde 02/09 ela é o `repeating-linear-gradient` da fileira (ver acima), e
   não mais um elemento: com a quebra em várias linhas, quem sabe quantas
   tábuas existem é o navegador, não o HTML. O `<span class="tabua">` saiu do
   markup junto. */

/* ── A COLUNA DA CAPA ─────────────────────────────────────────────────────
   A `.capa-cega` de hoje, só que UMA por tela em vez de vinte e seis — e por
   isso ela pode ser grande e ter medida em px, sem `cqw`. */
/* `sticky`: com o acervo inteiro em prateleiras empilhadas, a página rola —
   e uma coluna presa ao topo sairia de cena no terceiro livro, levando junto
   as quatro ações da obra em foco. Ela acompanha a rolagem e para quando o
   fim das prateleiras a alcança. */
.coluna-capa {
  flex: none; width: 248px;
  position: sticky; top: 1.6rem; align-self: flex-start;
  display: flex; flex-direction: column; gap: .55rem;
}
.coluna-capa .capa-grande {
  display: flex; flex-direction: column; justify-content: flex-end;
  aspect-ratio: 2 / 3; border-radius: 3px; padding: 26px 24px;
  background:
    linear-gradient(160deg, rgba(255,255,255,.12), rgba(0,0,0,.16)),
    var(--lombada, var(--t-cheio, var(--tenue)));
  /* Sombra própria, projetada para a ESQUERDA: a capa está de frente para
     quem olha, e a luz da casa vem de cima e da esquerda. */
  box-shadow: -2px 10px 26px rgba(34,33,29,.3);
  color: var(--sobre-lombada); overflow: hidden;
}
.coluna-capa .capa-titulo {
  font-family: var(--serif); font-weight: 600; font-size: 25px; line-height: 1.12;
  letter-spacing: -.01em; text-wrap: pretty;
  display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical;
  overflow: hidden;
}
.coluna-capa .capa-filete {
  display: block; height: 1px; background: rgba(255,255,255,.45);
  margin: 16px 0 12px; flex: none;
}
.coluna-capa .capa-autor {
  font-family: var(--sans); font-weight: 600; font-size: 9.5px; letter-spacing: .15em;
  text-transform: uppercase; opacity: .88;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.coluna-capa .tema {
  font-family: var(--sans); font-weight: 600; font-size: 10px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--tenue);
}
.coluna-capa .legenda {
  font-family: var(--sans); font-size: 12.5px; color: var(--tinta-2);
  font-variant-numeric: tabular-nums;
}
/* `sinal-texto`, e não `rotulo`: `.rotulo` é nome genérico demais, usado em
   quatro telas e no próprio harness de design — cuja regra de legenda de cena
   vestiu a primeira captura de versalete apagado («VOZ DE ESTÚDIO · 11H»). */
.coluna-capa .sinal-estudio { font-family: var(--sans); font-size: 12.5px; color: var(--tinta-2); }
.coluna-capa .sinal-estudio svg { color: var(--acento); }
.coluna-capa .acoes { display: flex; gap: .4rem; margin-top: .2rem; }
.coluna-capa .acoes .redondo {
  width: 34px; height: 34px; min-height: 34px; font-size: .95rem;
  border-color: var(--aro-fino);
}
.coluna-capa .acoes .excluir:hover, .coluna-capa .acoes .excluir:focus-visible {
  color: var(--perigo); border-color: var(--perigo);
}
.coluna-capa .aviso-estado { margin-top: .4rem; }

/* No iPad em retrato e no iPhone a coluna sai: 248px ali são metade da tela
   para mostrar um livro de cada vez. A prateleira continua inteira, e a capa
   volta a ser o que era antes de existir coluna — a vista Grade. */
@media (max-width: 899px) {
  .coluna-capa { display: none; }
}
/* A regra da grade 2×2 das ações saiu com a capa da prateleira (02/09): a
   fileira mostra LOMBADAS, e a lombada não carrega botão nenhum — quem tem as
   ações da obra em foco é a coluna da capa. */
/* A regra que engordava a capa de 104 para 124px em tela larga saiu com a
   capa: a lombada tira a largura da EXTENSÃO da obra, não da tela. */

/* ── O cartão é uma COLUNA, e o rodapé dele mora embaixo  (01/09) ──────────
   Sem isto, a fileira de ações cai onde o título terminar. Numa grade de cinco
   colunas isso põe cinco fileiras de botões em cinco alturas diferentes — e
   basta um título de seis linhas («O jardim das Aflições: de Epicuro à
   ressurreicão de César ; ensaio sobre o materialismo e a religião civil») para
   a coluna dele descer sozinha e a linha inteira perder o pé.

   Duas peças, e as duas são necessárias:

     · o `<li>` vira coluna e ESTICA até a altura da linha da grade (é o
       `align-items: stretch` que o grid já dá de graça, mas só serve se o item
       for um contêiner de altura cheia);
     · o `.alvo` fica com `flex: 1` e come a sobra, empurrando `.acoes` para a
       base. `margin-top: auto` faria o mesmo — mas o `flex: 1` deixa a área
       clicável ocupar o vazio, e num cartão de livro o vazio embaixo do autor
       ainda é o livro.

   Vale na grade e na fileira: os dois são contêiner flex, e o cartão não
   precisa saber em qual está. */
.obra {
  position: relative;
  display: flex; flex-direction: column; height: 100%;
}
.obra .alvo {
  display: flex; flex-direction: column; flex: 1;
  text-decoration: none; color: inherit;
}

/* ── A capa é DESENHADA  (prancha 1f, candidato «papel manchado») ──────────
   «A capa não ilustra a obra: ela veste a matiz do tema de estudo.»

   Papel do tema com uma mancha radial a 62% da matiz, entrando por um canto
   sorteado pelo hash do slug (`capa.mjs`), título em Literata por cima e um
   filete a 35% de tinta. Nenhuma imagem, nunca — e por isso nenhum `<img>`,
   nenhuma rede, nenhum estado de carregamento e nada que possa falhar.

   Escolhido entre os três candidatos pelo que a prancha registra: é o que
   sobrevive melhor a 84px, e 84px é o tamanho da prateleira. */
.obra .capa {
  display: flex; align-items: flex-end; width: 100%; aspect-ratio: 2 / 3;
  border-radius: var(--raio); border: 1px solid var(--borda-controle);
  background: var(--papel-elev);
  overflow: hidden; position: relative; box-sizing: border-box;
  padding: .55rem .5rem .5rem;
}
/* Só o manchado tinge o filete de tinta: no campo cheio ele é branco a 45%,
   declarado no bloco da capa cega. */
.obra .capa-manchado .capa-titulo {
  color: var(--tinta);
  border-top-color: color-mix(in srgb, var(--tinta) 35%, transparent);
}
.obra .capa-manchado::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(74% 62% at var(--mancha, 18% 14%),
    color-mix(in srgb, var(--t, var(--tenue)) 62%, transparent), transparent 72%);
}
/* O filete, acima do título. A 35% de tinta ele separa sem virar moldura —
   moldura é o que a prancha manda não ter. */
.obra .capa-titulo {
  position: relative; z-index: 1;
  /* Largura cheia, e não a do texto: o filete é uma RÉGUA sobre o rodapé da
     capa, e um filete do tamanho da palavra vira sublinhado — que é outra
     coisa, e a que a prancha não pediu. */
  width: 100%; box-sizing: border-box;
  font-family: var(--serif); font-weight: 600;
  font-size: .72rem; line-height: 1.22;
  /* `inherit`, e não `var(--tinta)`. Este bloco nasceu para o «papel manchado»,
     onde o título é tinta sobre papel; a capa de campo cheio põe texto CLARO
     sobre a matiz, e declarar a cor aqui vencia a herança do pai — o título
     saía preto sobre roxo, ilegível. Quem decide a cor do texto é o campo. */
  color: inherit;
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
  overflow: hidden;
  padding-top: .4rem;
  border-top: 1px solid currentColor;
  text-wrap: pretty;
}

/* O traço do progresso, na base da capa. Fino de propósito: é informação de
   canto de olho, e a mesma semântica do anel da bolha no artigo. */
.obra .traco {
  display: block; height: 3px; margin-top: -3px; position: relative;
  border-radius: 0 0 var(--raio) var(--raio); overflow: hidden;
  background: color-mix(in srgb, var(--tinta) 12%, transparent);
}
/* `--t`, e não `--acento` (2026-09-01): é a mesma regra que a prancha 1c fixa
   para a lista — a barra de progresso veste a matiz do TEMA, nunca a cor do
   app. O traço da capa é a mesma informação noutra tela, e estava dizendo
   «cyber» com a voz da marca. */
.obra .traco > span { display: block; height: 100%; background: var(--t, var(--acento)); }

/* ── O título ocupa DUAS linhas, sempre  (01/09) ───────────────────────────
   Alinhar o rodapé embaixo conserta o desalinhamento e deixa outra feiura no
   lugar: com um título de uma linha ao lado de um de seis, o cartão curto fica
   com um rombo de branco entre o autor e os botões. O que a grade quer é o
   contrário disso — legendas do mesmo tamanho, como numa estante de verdade as
   lombadas têm a mesma altura.

   `-webkit-line-clamp` corta o que passa de duas linhas e põe reticências, e o
   `min-height` reserva as duas mesmo quando só há uma. O par é que iguala; um
   sozinho resolve metade.

   O texto continua INTEIRO no DOM — o corte é visual, então o leitor de tela
   ouve o título completo e a busca o encontra. E a capa logo acima já cortava
   com reticências desde a prancha 1f: duas medidas diferentes do mesmo título
   na mesma peça seria o estranho. */
.obra .titulo {
  font-family: var(--serif); font-size: .9rem; line-height: 1.3;
  margin-top: .5rem; font-weight: 600; text-wrap: balance;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;
  min-height: calc(2 * 1.3em);
}
.obra .autor { display: block; font-family: var(--sans); font-size: .75rem; color: var(--tinta-2); }
.obra:not(.lombada) .sinal-estudio { display: flex; margin-top: .3rem; }
/* A legenda «71% · canto XXII» só existe em «Lendo agora» — quem decide é o
   `montarObra`, não o CSS, porque é informação e não aparência. Aqui só a voz:
   sans, miúda e em `--tenue`, que é o registro do que se lê de canto de olho. */
.obra .legenda {
  display: block; font-family: var(--sans); font-size: .7rem; color: var(--tenue);
  margin-top: .15rem; font-variant-numeric: tabular-nums;
}
/* O acento no título é da vista GRADE, onde ele é texto sobre papel e o realce
   precisa de cor. Na LOMBADA ele é texto claro sobre campo escuro: o acento
   pinta o título de brasa por cima do bordô — visto no iPad em 02/09, no livro
   que o toque levantou. Lá o realce já existe e é outro: o livro sobe 14px,
   que é o gesto de tirá-lo da prateleira. */
.obra:not(.lombada) .alvo:hover .titulo,
.obra:not(.lombada) .alvo:focus-visible .titulo { color: var(--acento); }

/* ── As cinco ações da GRADE cabem numa LINHA  (02/09) ────────────────────
   Duas tentativas antes desta, e as duas foram vistas no aparelho:

   1. **Cinco em `flex` sem quebra**, herdado de quando eram quatro: 5×36px
      mais os vãos dão ~196px numa coluna que pode ter 144, e os botões foram
      parar por cima do cartão vizinho.
   2. **Grade de 3+2**: não transborda, e fica torto — duas fileiras
      desiguais de círculos embaixo de cada capa, vinte e seis vezes. «Ficou
      feio», e estava.

   O que faz a linha caber é o par: o botão desce de 36 para 30px (o registro
   do alvo secundário, que o `✎` do destaque já usa a 26) e a coluna sobe de
   9 para 10,5rem. 5×30 + 4×3 = 162px numa coluna que nunca é menor que 168.

   A coluna maior não é custo: no iPad ela troca cinco capas apertadas por
   quatro maiores, que é o que uma grade de capas quer mostrar. */
/* ── E eram SEIS, não cinco  (17/09) ──────────────────────────────────────
   O lápis de editar título e autor entrou na fileira no MESMO dia, depois da
   conta de cima: 6×30 + 5×3 = 195px numa coluna de 171 no iPhone. O ✕ de um
   cartão pousava sobre o ✓ do vizinho, e o da coluna direita saía da tela e
   dava à página inteira uma rolagem lateral. O teste cobrava `lado × 5`, com
   o cinco escrito à mão, e seguiu verde.

   Agora o círculo é ELÁSTICO: 30px quando cabe, cedendo até 26 (o registro do
   `✎` do destaque) quando não cabe, com 2px de vão. Seis a 26 com cinco vãos
   medem 166px, dentro dos 168 da coluna mínima; no iPad e no Mac, onde a
   coluna é larga, nada muda. `aspect-ratio` mantém o círculo quando a largura
   cede, e `align-items: center` impede o esticamento de desfazê-lo. */
/* ── E são SETE, em duas fileiras  (18/09, spec 61) ──────────────────────
   «Mandar para lista…» entrou como sétima. Sete círculos de 26px com vão
   medem 194px, e a coluna mínima é 168 — o teto para o iPhone manter duas
   colunas é 171. Encolher o círculo abaixo de 26 tira o alvo; alargar a
   coluna põe o iPhone numa coluna só. Duas fileiras de quatro, e a divisão
   tem sentido: em cima, onde o livro está (✓ ⤓ ▤ e a escrivaninha); embaixo,
   o que fazer com ele (a lista, o lápis e o ✕). 4×30 + 3×4 = 132px. */
.obra .acoes {
  display: grid; grid-template-columns: repeat(4, 30px); gap: 4px;
  justify-content: start; align-items: center; margin-top: .4rem;
}
/* ── O tamanho que faltava, e faltava desde antes desta rodada  (2026-09-01)
   A regra de `.redondo` diz com todas as letras que «a forma é dele, o TAMANHO
   é do contexto» — e a estante nunca disse o seu. Os botões herdavam 44px de
   altura do `--alvo` do núcleo e tiravam a largura do CONTEÚDO: um glifo de
   uma letra, ~12px. Quatro elipses verticais de 12×44.
   Não apareceu antes porque a grade dava colunas de 144px e as elipses tinham
   espaço de sobra para não parecerem apertadas; a fileira de 104px as pôs lado
   a lado e o defeito ficou visível. Ele já estava lá.
   36px é o registro do `.linha-progresso` (32) mais folga, e cabe duas por
   fileira nos 104px — com a quebra logo abaixo, as quatro ficam em 2×2. */
.obra .acoes .redondo {
  flex: 0 1 30px; min-width: 26px; height: auto; min-height: 0;
  aspect-ratio: 1; font-size: .82rem;
}


/* ── O alternador de vista da estante  (prancha 1e) ────────────────────────
   «Grade | Prateleiras», um segmentado ao lado do título. Duas vistas do mesmo
   acervo: a prateleira agrupa por estado e rola; a grade mostra tudo de uma
   vez, ordenado pela última leitura.

   `role="tablist"` e `aria-selected` em vez de `aria-pressed`: são vistas
   mutuamente exclusivas do mesmo conteúdo, que é exatamente o que uma aba é —
   e dois botões de alternar independentes diriam a quem usa leitor de tela que
   as duas podem estar ligadas ao mesmo tempo. */
.cabeca-estante {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; margin: 0 0 1rem;
}
.cabeca-estante .titulo-tela { margin: 0; }
.vistas {
  display: inline-flex; padding: 3px; gap: 2px;
  background: var(--papel-elev-2); border-radius: 999px;
}
.vistas .vista {
  font-family: var(--sans); font-size: .78rem; font-weight: 500;
  color: var(--tinta-2); background: none; border: 0; cursor: pointer;
  padding: .4rem .9rem; border-radius: 999px; min-height: 34px;
}
.vistas .vista[aria-selected="true"] {
  background: var(--papel-elev); color: var(--tinta);
  box-shadow: var(--sombra-pousada);
}
.vistas .vista:hover, .vistas .vista:focus-visible { color: var(--acento); }

/* A grade: aqui SIM o `auto-fill` é a resposta certa, e pelo motivo que a
   prateleira não tinha. A vista Grade existe justamente para mostrar o
   conjunto todo de uma vez — quebrar em linhas é o que ela promete, e o iPad
   girando continua sendo o caso comum. */
/* 10,5rem (168px) desde 02/09, e o número sai da fileira de ações: cinco
   alvos de 30px com 3px de vão medem 162, e uma coluna que possa ser menor que
   isso é uma coluna em que os botões transbordam. O mínimo da grade e a largura
   da fileira são a MESMA decisão — separá-los foi o que deixou os cinco botões
   caírem por cima do cartão vizinho. */
.grade-estante {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
  gap: 1rem;
}

/* ── A capa «tipográfica cega»  (prancha 1f, candidato 1 — escolhido em 01/09)
   Campo cheio na matiz do tema, título em Literata sobre ele, filete a 45% de
   branco e o autor em versalete. Nenhuma imagem, nunca.

   As medidas vêm da prancha, que compõe sobre uma capa de 100px: título 17px,
   filete de 1px com 8px/6px de folga, autor 7,5px com 0,14em de entreletra.
   Aqui elas viram `cqw` — a prateleira desenha a 104px e o Mac a 124, e uma
   capa que muda de tamanho com o título fixo deixa de ser a mesma capa. Com
   unidade de contêiner a proporção atravessa os dois. */
.obra .capa-cega {
  /* `stretch`, desfazendo o `align-items: flex-end` de `.obra .capa`. Aquele
     valor servia ao manchado, que é `flex-direction: row` e queria o título no
     rodapé; aqui a direção é `column`, e no eixo cruzado `flex-end` empurra o
     texto para a DIREITA. Título curto saía alinhado à direita e título longo
     à esquerda, na mesma prateleira. */
  align-items: stretch;
  container-type: inline-size;
  border-radius: 2px;
  /* A tinta da LOMBADA, e não mais a matiz cheia (02/09): é o mesmo livro nas
     duas vistas, e ele não pode mudar de cor ao trocar de vista. A cadeia de
     reserva desce da lombada para a matiz cheia e daí para o cinza. */
  background: var(--lombada, var(--t-cheio, var(--t, var(--tenue))));
  box-shadow: var(--sombra-pousada);
  /* O padding em `%`, e não em `cqw`, e isto vale um comentário porque custou
     uma rodada: `container-type: inline-size` faz o elemento ser contêiner
     para os DESCENDENTES dele, não para si mesmo. Um `cqw` escrito aqui
     resolve contra o contêiner de fora — a capa de 104px ganhou 12% de 1150 e
     virou uma caixa de 266. Percentual resolve contra o pai, que é o que se
     queria. */
  padding: 12% 11%;
  display: flex; flex-direction: column; justify-content: flex-end;
  /* Cravado, e não `--sobre-acento`: este branco é o papel da CAPA, e ele tem
     de ser o mesmo sobre as cinco matizes — um token que muda por tema faria a
     série mudar de cor de texto conforme a hora do dia. */
  color: #fdf6ef;
  overflow: hidden;
}
.obra .capa-cega .capa-titulo {
  font: 600 17cqw/1.1 var(--serif); letter-spacing: -.01em;
  color: inherit;
  /* Sem filete próprio: aqui ele é um `<span>` dedicado, entre título e autor,
     porque a prancha o quer com o branco a 45% e uma folga própria de cada
     lado. O `border-top` do bloco genérico serve ao manchado, que não tem
     autor embaixo. */
  border-top: 0; padding-top: 0; width: auto;
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
  overflow: hidden; text-wrap: pretty;
}
.obra .capa-cega .capa-filete {
  display: block; height: 1px; background: rgba(255,255,255,.45);
  margin: 8% 0 6%; flex: none;
}
.obra .capa-cega .capa-autor {
  font: 600 7.5cqw/1 var(--sans); letter-spacing: .14em;
  text-transform: uppercase; opacity: .88;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ── Visível para o leitor de tela, invisível para o olho ──────────────────
   A prancha 1c vai da marca direto ao segmentado: não há título «Inbox» acima
   das abas. Mas uma tela sem `<h1>` é uma regressão de navegação por
   cabeçalhos, e trocar acessibilidade por diagramação é troca ruim — então o
   título fica no documento e sai da vista.

   `clip-path: inset(50%)` e não `display:none` nem `visibility:hidden`: os
   dois últimos tiram o elemento da árvore de acessibilidade junto, que é
   exatamente o oposto do que se quer aqui. Mesma técnica do
   `#colar input[type=file]`, e pelo mesmo motivo. */
.so-leitor {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}



/* ═══════════════════════════════════════════════════════════════════════════
   A ESCRIVANINHA  (spec 23)
   ═══════════════════════════════════════════════════════════════════════════
   A quarta seção, a rota do estudo e a revisão. Nada aqui inventa gramática:
   a lista é a lista, os painéis são da família do `#nota`, e a cápsula do
   estudo é uma terceira cápsula na pilha que já existe.
   ═════════════════════════════════════════════════════════════════════════ */

/* ── A pilha ganha uma QUARTA cápsula, e SÓ na rota do estudo ──────────────
   Duas parcelas mudam aqui, e as somas que dependem delas se refazem sozinhas
   porque todas moram no mesmo `body` (ver a nota da geometria, lá em cima):

     · a cápsula do estudo entra no topo;
     · a MÃO perde um item — o `⇧` não existe na escrivaninha, onde
       compartilhar é o estudo inteiro e mora no `⋯`.

   O TETO é 520px, e ele é requisito, não estimativa: a coluna tem de caber em
   iPad retrato com o texto embaixo. O `npm run design` mede. */
body[data-rota="estudo"] {
  /* O «Seguir» mais os DOIS glifos (original, `⋯`) e os dois fios. Eram três
     até a F1 da spec 51, que tirou o ▤ dos cartões da cápsula e deixou a conta
     com o glifo que não existe: 206px declarados contra 158 reais, a coluna do
     Mac 24px abaixo do centro e a da bancada 48px «mais alta» do que é. Quem
     cobra é o `npm run design`, pela folga de cima igual à de baixo. */
  --capsula-estudo-h: calc(var(--capsula-seguir-h) + var(--capsula-item) * 2 + 2px);
  --capsula-mao-h: calc(var(--capsula-item-texto) * 2 + 2px);
  /* A cápsula da bancada (spec 43 §7.1): a face alta, como o «Seguir», mais
     os QUATRO glifos (`</>`, `>_`, `▶▶`, `✕`) e os dois fios. Ela mora aqui,
     e não no `:root`, pela regra desta seção: parcela que uma rota redeclara
     mora no elemento em que a rota a redeclara. */
  --capsula-bancada-h: calc(var(--capsula-seguir-h) + var(--capsula-item) * 4 + 2px);
  --bancada-bloco: 0px;
  --pilha-h: calc(var(--bancada-bloco) + var(--capsula-estudo-h) + var(--capsula-gap)
    + var(--capsula-pagina-h) + var(--capsula-gap)
    + var(--voz-bloco) + var(--capsula-mao-h));
  --y-aa: calc(var(--capsula-mao-h) + var(--capsula-gap) + var(--voz-bloco));
  --y-progresso: calc(var(--y-aa) + var(--capsula-item));
  --y-velocidade: calc(var(--capsula-mao-h) + var(--capsula-gap) + var(--capsula-item));
}

/* ── E a QUINTA cápsula, só quando há laboratório em cena  (spec 43 §7.1) ──
   `--bancada-bloco` é a cápsula MAIS o gap abaixo dela, e vale zero quando
   ela não existe — o mesmo desenho do `--voz-bloco`, e pela mesma razão: uma
   soma que muda de número de parcelas dá `calc()` inválido, e `calc()`
   inválido não desenha nada de errado, só faz o Mac centrar a coluna pela
   altura de antes. Quem acende o atributo é a própria cápsula, que o escreve
   ao nascer e o apaga ao sair (`capsula-bancada.mjs`). */
body[data-rota="estudo"][data-bancada] {
  --bancada-bloco: calc(var(--capsula-bancada-h) + var(--capsula-gap));
}

/* O «Seguir» é o único item da pilha inteira com rótulo em TEXTO e com o
   acento em campo — é a ação primária da tela, e a única que o leitor procura
   sem saber onde está. As irmãs continuam glifos de 48px. */
#capsula-estudo > button { font-size: .8rem; }
/* ── O «Seguir»: DUAS linhas, e a razão é a largura da cápsula ─────────────
   A pilha tem 52 px, e um rótulo de uma linha só ali cabia em três letras —
   «Perguntas da parte 2» saía como «Per…», que é pior que glifo nenhum: o
   botão promete uma palavra e entrega o começo dela. A captura de 03/09
   mostrou isso, e nenhum teste de estado veria.
   Então o item é ALTO (a spec já pedia «item alto, com rótulo»): a ação em
   cima, o destino embaixo, ambos em caixa pequena. O rótulo inteiro vive no
   `title` e no `aria-label`. */
#estudo-seguir {
  height: var(--capsula-seguir-h);
  background: var(--acento); color: var(--sobre-acento);
  padding: 4px 2px 5px; text-align: center;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; overflow: hidden;
}
#estudo-seguir .acao {
  font-size: .58rem; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  opacity: .82; line-height: 1;
}
#estudo-seguir .alvo {
  font-size: .57rem; font-weight: 600; line-height: 1.25; letter-spacing: -.005em;
  /* Duas linhas no máximo, e a quebra é no ESPAÇO — nunca no meio da palavra.
     Com `overflow-wrap: anywhere`, «Perguntas 2» saía «Pergunt / as 2», que é
     o mesmo defeito do «Per…» com mais linhas: o botão promete uma palavra e
     entrega um pedaço dela. Quebrando no espaço, sai «Perguntas / 2». */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; max-width: 100%; overflow-wrap: normal; hyphens: none;
}
#estudo-seguir:hover, #estudo-seguir:focus-visible { color: var(--sobre-acento); opacity: .92; }
#estudo-seguir[disabled] { opacity: .55; cursor: default; }
/* Enquanto gera, o botão é inerte E parece inerte: clicar duas vezes não gera
   duas vezes (a API recusa com 409), mas um botão que aceita o toque e não faz
   nada é pior que um desligado. */
/* ── E ela veste o CROMO, não o papel  (05/09) ─────────────────────────────
   Nasceu com `--papel-elev-2`/`--tinta-2`, que é o campo esmaecido certo para
   um botão inerte sobre PAPEL. A cápsula, porém, é cromo grafite nos três
   temas desde a repaginação de 02/09 — e ali um campo de papel claro vira a
   coisa mais brilhante da coluna. Medido em 7,5:1 nos três temas
   (`espera.test.mjs`), um degrau abaixo das irmãs porque inerte é o que ele é. */
#estudo-seguir.gerando { background: var(--cromo-2); color: var(--cromo-tinta-2); }
/* ── Mas «gerando» NÃO se apaga como «indisponível»  (03/09) ───────────────
   O botão é `disabled` enquanto escreve — e o `[disabled]` acima deita
   `opacity: .55` sobre ele. Somado à tinta já esmaecida, o rótulo da espera
   media **2,30 : 1** no claro (2,48 no sépia, 2,78 no escuro), contra o piso
   de 4,5 — o texto que o leitor mais encara na tela era o menos legível dela,
   e a queixa que originou o relógio era justamente não saber se algo estava
   acontecendo.

   A opacidade volta a 1: quem diz «inerte» aqui são as cores trocadas, e uma
   coisa que está TRABALHANDO não se anuncia como coisa que não está
   disponível. Medido em `espera.test.mjs`, nos três temas. */
#estudo-seguir.gerando[disabled] { opacity: 1; }
/* ── E quando o próprio pedido falha  (03/09) ──────────────────────────────
   Mesmo campo esmaecido do «gerando», tinta do perigo — medido em 5,72 : 1 no
   claro, 4,95 no sépia, 5,77 no escuro. O botão continua clicável, porque
   tentar de novo é o gesto óbvio e o motivo inteiro está no `title`. */
/* O irmão da espera, e pela mesma razão veste o mesmo campo de cromo. A tinta
   passa a ser `--cromo-perigo` — o `--perigo` de papel dá 2,50:1 sobre grafite
   no claro, e a regra é clarear a TINTA, nunca o campo. O token já existia
   desde 04/09, criado por este mesmo motivo noutro botão da mesma coluna. */
#estudo-seguir.falhou { background: var(--cromo-2); color: var(--cromo-perigo); }

/* ═══════════════════════════════════════════════════════════════════════════
   A CÁPSULA DA BANCADA  (spec 43 §7.1)

   A barra do pé da página saiu — ela era `sticky` sobre o texto e, no iPad,
   nascia debaixo da navegação inferior (visto em 08/09: «Rodar até aqui» e
   «Reiniciar» cobertos). O que entra é uma cápsula no TOPO da pilha, com os
   mesmos 52px das irmãs e a mesma anatomia do «Seguir»: face alta de duas
   linhas e quatro glifos abaixo.

   As regras são gêmeas das do `#estudo-seguir` e ficam escritas em separado
   de propósito — juntar os dois seletores quebraria as conferências que leem
   `#estudo-seguir { … }` por regex. Quem cobra que elas não divirjam é o
   `bancada.test.mjs`, que lê esta folha.
   ═════════════════════════════════════════════════════════════════════════ */
#capsula-bancada > button { font-size: .8rem; }
#bancada-face {
  height: var(--capsula-seguir-h);
  background: var(--acento); color: var(--sobre-acento);
  padding: 4px 2px 5px; text-align: center;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; overflow: hidden;
}
#bancada-face .acao {
  font-size: .58rem; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  opacity: .82; line-height: 1;
}
#bancada-face .alvo {
  font-size: .57rem; font-weight: 600; line-height: 1.25; letter-spacing: -.005em;
  /* Duas linhas, quebra no espaço — e o hífen de sílaba do «reconec­tando…»,
     que é a única palavra do mostrador que não cabe numa linha de 52px. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; max-width: 100%; overflow-wrap: normal; hyphens: manual;
  font-variant-numeric: tabular-nums;
}
#bancada-face:hover, #bancada-face:focus-visible { color: var(--sobre-acento); opacity: .92; }
/* Subindo e caído a face é cromo, e não acento: ela ainda é o mostrador, mas
   não é convite — o acento cheio numa coluna grafite é o que chama a mão, e
   a mão não tem nada a fazer enquanto a task nasce. A tinta é a clara sobre
   cromo, nunca o campo clareado (a regra de 05/09). */
#bancada-face[data-estado="subindo"] { background: var(--cromo-2); color: var(--cromo-tinta-2); }
#bancada-face[data-estado="caiu"] { background: var(--cromo-2); color: var(--cromo-perigo); }
#bancada-face[data-estado="falhou"] { background: var(--cromo-2); color: var(--cromo-perigo); }
#bancada-face[data-estado="encerrada"] { background: var(--cromo-2); color: var(--cromo-tinta-2); }
/* Rodando o campo é acento e o mostrador pulsa: é o único estado em que tocar
   INTERROMPE, e ele tem de se distinguir do «pronta» sem trocar de lugar. */
#bancada-face[data-estado="rodando"] .acao { animation: bancada-pulso 1.1s ease-in-out infinite; }
/* Inerte é o «sem relé», e só ele: o mostrador não se apaga por estar
   ocupado — quem trabalha não se anuncia como indisponível (03/09). */
#bancada-face[disabled] { opacity: .55; cursor: default; }
#bancada-fechar[disabled], #bancada-ate-aqui[disabled] { opacity: .45; cursor: default; }

/* ── Numa janela BAIXA, a bancada recolhe «Até aqui» e «Fechar»  (43 §7.1) ─
   Os dois têm gêmeos na aba Shell da caixa; «Editar» e «Caixa» não têm outro
   lugar, e por isso ficam. O corte é 900px porque é onde a coluna com CINCO
   cápsulas deixa de caber: 866 (pilha) + 90 (--pilha-0) + 24 (folga) = 980,
   e o degrau redondo abaixo disso é 900.

   E o token encolhe junto. Esconder dois itens sem mexer em
   `--capsula-bancada-h` deixaria a altura DECLARADA 96px maior que a real, e
   é por ela que o Mac centra a coluna — a folga de cima abriria pela
   diferença. */
@media (max-height: 900px) {
  #bancada-ate-aqui, #bancada-fechar { display: none; }
  body[data-rota="estudo"] {
    --capsula-bancada-h: calc(var(--capsula-seguir-h) + var(--capsula-item) * 2 + 2px);
  }
}

/* ── Numa janela BAIXA, a cápsula recolhe ao essencial  (03/09) ────────────
   Com as três cápsulas abertas a coluna mede 584px — medido no harness, com
   todas as bolhas em cena. O corte é o PONTO EM QUE ELA NÃO CABE, e não a
   altura de um aparelho (a lição de 02/09 no Tabula, com o iPhone que ficava
   dez pixels fora da media query). A conta, no modo barra, que é o pior caso
   por ser o único que ancora a pilha embaixo:

       584 (pilha) + 90 (--pilha-0) + 24 (folga em cima) = 698

   Daí 720px, o degrau redondo logo acima. Um iPhone em retrato tem ~780 de
   viewport e NÃO recolhe; um iPad com o teclado aberto recolhe, que é
   exatamente quem precisa. Recolhida, a conta cai para 488 + 90 + 24 = 602.

   O que sobrevive ao aperto é o par que não tem substituto: a ação primária
   («Seguir») e a saída («⋯»). O glifo que recolhe continua alcançável pelo
   menu, que é a lista completa — recolher não pode virar sumir. */
@media (max-height: 720px) {
  #estudo-original { display: none; }
}

/* ── A visão: a partida, o mapa e o que ficou de fora  (03/09) ─────────────
   O mapa é DADO — cada unidade com o peso e o botão de riscar —, e a lista do
   que ficou de fora existe para o corte de ruído ser conferível: motivo e
   contagem, item por item. */
.partida {
  border-left: 3px solid var(--acento); padding: .2rem 0 .2rem 1rem;
  margin: 0 0 1.6rem; max-width: var(--measure);
}
.partida .rotulo {
  font-family: var(--sans); font-size: .72rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--acento); margin: 0 0 .3rem;
}
.partida .pergunta {
  font-family: var(--corpo); font-size: 1.05rem; line-height: 1.5;
  color: var(--tinta); margin: 0;
}
.mapa-estudo {
  margin: 2.5rem auto 0; max-width: var(--measure);
  border-top: 1px solid var(--regra); padding-top: 1.2rem;
  font-family: var(--sans);
}
.mapa-estudo h2 {
  font-size: .74rem; letter-spacing: .09em; text-transform: uppercase;
  color: var(--tenue); margin: 0 0 .8rem;
}
.mapa-estudo .unidades { list-style: none; margin: 0; padding: 0; }
.mapa-estudo .unidades li {
  display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .6rem; padding: .45rem 0;
  border-bottom: 1px solid var(--papel-borda-fina);
}
.mapa-estudo .termo { flex: 1 1 auto; font-size: .94rem; color: var(--tinta); }
/* A ideia-mestra é uma proposição: o título nomeia, o enunciado DIZ. Ele toma
   a linha inteira (`flex-basis: 100%` quebra a linha do flex) para não
   disputar espaço com o «Já domino» num telefone. */
.mapa-estudo .enunciado {
  flex: 1 0 100%; font-size: .82rem; line-height: 1.4; color: var(--tenue);
}
.mapa-estudo .peso { color: var(--acento); font-size: .7rem; letter-spacing: .1em; }
.mapa-estudo .domino {
  font-size: .78rem; padding: .2rem .55rem; min-height: 0; flex: none;
}
/* Riscada, não sumida: o leitor tem de ver o que ele mesmo tirou. */
.mapa-estudo .dominada .termo { color: var(--tenue); text-decoration: line-through; }
.mapa-estudo .dominada .peso { opacity: .35; }
.mapa-estudo .dominada .enunciado { opacity: .5; }
.mapa-estudo details { margin-top: 1rem; }
.mapa-estudo summary {
  font-size: .8rem; color: var(--tinta-2); cursor: pointer;
}
.mapa-estudo .fora-do-estudo ul { list-style: none; margin: .5rem 0 0; padding: 0; }
.mapa-estudo .fora-do-estudo li {
  display: flex; justify-content: space-between; font-size: .82rem;
  color: var(--tenue); padding: .2rem 0;
}
.mapa-estudo .partida-resposta p {
  font-family: var(--corpo); font-size: .95rem; line-height: 1.55;
  color: var(--tinta-2); margin: .4rem 0 0;
}

/* ── O fecho do estudo  (spec 51) ──────────────────────────────────────────
   Na conclusão: o laboratório sob demanda (só no técnico) e a passagem que
   ficou (nos gêneros de ressonância). Da família do juízo da parte — no fim do
   texto, discreto, e sem campo nenhum dentro do `<main>`: a frase se escreve no
   painel `#ressonancia`, fora dele. */
.fecho-estudo {
  margin: 2.5rem auto 0; max-width: var(--measure);
  border-top: 1px solid var(--regra); padding-top: 1.2rem;
  display: flex; flex-direction: column; gap: 1.4rem;
}
.fecho-estudo h2 {
  font-family: var(--sans); font-size: .74rem; letter-spacing: .09em;
  text-transform: uppercase; color: var(--tenue); margin: 0 0 .5rem;
}
.fecho-estudo .sub { font-family: var(--sans); font-size: .9rem; color: var(--tinta-2); margin: 0 0 .6rem; }
.fecho-estudo .aviso { font-family: var(--sans); font-size: .86rem; color: var(--perigo); margin: 0 0 .6rem; }
.fecho-estudo .passagem, #ressonancia .escolhida {
  margin: 0 0 .5rem; padding: .4rem .8rem; border-left: 3px solid var(--acento);
  font-family: var(--corpo); font-size: .96rem; line-height: 1.55; color: var(--tinta);
}
.fecho-estudo .frase { font-family: var(--corpo); font-style: italic; color: var(--tinta-2); margin: 0 0 .6rem; }
/* O parágrafo tocado, enquanto o painel está aberto. Contorno e não fundo: o
   fundo é dos destaques, e confundir os dois faria a escolha parecer marcação. */
.prosa .passagem-escolhida { outline: 2px solid var(--acento); outline-offset: 4px; border-radius: 4px; }
#ressonancia .dica { font-family: var(--sans); font-size: .88rem; color: var(--tinta-2); margin: 0 0 .7rem; }

/* ── O juízo da parte: um toque, três palavras  (03/09) ────────────────────
   O instrumento que transforma a reclamação verbal num dado. Discreto de
   propósito: é pergunta de saída, não parte do estudo. */
.juizo-parte {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin: 1.6rem auto 0; max-width: var(--measure);
  font-family: var(--sans);
}
.juizo-parte .rotulo { font-size: .78rem; color: var(--tenue); }
.juizo-parte .btn { font-size: .78rem; padding: .2rem .6rem; min-height: 0; }
.juizo-parte .btn.ativo { border-color: var(--cromo-acento); color: var(--cromo-acento); }

/* ── A trilha ───────────────────────────────────────────────────────────── */
/* ── A coluna, quando a marginália liga a GRADE  (03/09) ───────────────────
   Com `data-marginalia="sim"`, `body[data-leitura] main` vira uma grade de
   duas colunas: o texto e a margem. A grade espera DOIS filhos — a folha e o
   painel —, e a rota do estudo acrescenta outros: a trilha e a antessala.
   Sem dizer a coluna, o segundo filho cai na coluna da MARGEM, e foi o que
   apareceu no Mac: a trilha à esquerda e o título do estudo espremido na
   faixa da direita.
   Os três pertencem à coluna do texto, e é isso que a linha abaixo declara —
   inofensiva quando não há grade nenhuma. */
.trilha, .antessala, .erro-estudo { grid-column: 1; }

.trilha { max-width: var(--measure); margin: .4rem auto 1.2rem; padding-inline: 1.1rem; }
.trilha ol {
  list-style: none; margin: 0; padding: 0;
  /* `align-items: center`: metade dos passos é `<button>` e metade é `<span>`,
     e os dois têm linhas de base diferentes — sem isto a trilha sai em
     degraus, com «Início» acima de «Pré». A captura de 03/09 mostrou.  */
  display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .45rem;
  font-family: var(--sans); font-size: .74rem;
}
.trilha .passo { display: flex; }
.trilha .passo > span, .trilha .passo > button {
  display: block; padding: .18rem .5rem; border-radius: 999px;
  border: 1px solid var(--papel-borda-fina); background: none;
  color: var(--tenue); font: inherit; line-height: 1.5;
}
.trilha .passo > button { cursor: pointer; }
/* O ponto diz «esta parte já tem perguntas escritas» — o que antes custava uma
   pastilha inteira ao lado. `currentColor` para acender junto com a pastilha
   quando ela é a corrente. */
.trilha .ponto {
  display: inline-block; width: 4px; height: 4px; border-radius: 50%;
  background: currentColor; opacity: .55; margin-left: .3rem; vertical-align: middle;
}
.trilha .passo.pronto > span, .trilha .passo.pronto > button {
  color: var(--tinta-2); border-color: var(--regra);
}
/* O laboratório ainda não montado (spec 51, 14/09): o tracejado diz «opcional,
   ainda não existe» sem apagar a porta. Antes de `.atual`/`.lendo`, que vencem
   por cima quando coincidem. A borda é `--tenue` e não `--regra`: no claro e
   no sépia a `--regra` some contra o papel, e o tracejado — que É o sinal —
   desaparecia (captura do harness, 14/09). */
.trilha .passo.opcional > span, .trilha .passo.opcional > button {
  border-style: dashed; border-color: var(--tenue); color: var(--tinta-2);
}
/* `.atual` = onde o ESTUDO está (o cursor). Campo cheio: é o que se vê de
   longe, e responde «até onde eu cheguei». */
.trilha .passo.atual > span, .trilha .passo.atual > button {
  background: var(--acento); color: var(--sobre-acento); border-color: transparent; font-weight: 600;
}
/* `.lendo` = o documento em CENA. Anel, não campo: são duas perguntas
   diferentes («até onde cheguei» e «onde estou agora») e elas caem na mesma
   pastilha na maior parte do tempo — dois campos cheios seriam a mesma tinta
   dizendo duas coisas. O anel se lê por cima do campo quando coincidem. */
.trilha .passo.lendo > button, .trilha .passo.lendo > span {
  border-color: var(--acento); color: var(--acento); font-weight: 600;
  box-shadow: 0 0 0 1px var(--acento);
}
.trilha .passo.lendo.atual > button, .trilha .passo.lendo.atual > span {
  color: var(--sobre-acento);
  box-shadow: 0 0 0 2px var(--papel), 0 0 0 3px var(--acento);
}

/* ── A ESCRIVANINHA: a ficha de estudo  (03/09) ────────────────────────────
   A lista era texto cru sobre a mesa. Ao lado do cartão da inbox e das
   lombadas da estante ela parecia um rascunho — e era, no sentido literal de
   nunca ter recebido desenho.

   A ficha herda o que dá coerência ao app (a lombada de 3px na matiz do tema,
   o título em serifa, a sobrancelha do cluster) e acrescenta o que só ela tem:
   a RÉGUA DAS PARTES. É o que responde de longe a pergunta que traz alguém a
   esta tela — «onde eu parei?» — sem precisar abrir nada.
   ═════════════════════════════════════════════════════════════════════════ */
.cabeca-escrivaninha { max-width: var(--measure); margin: 0 auto .2rem; padding: 0 1.1rem; }

.caderno, .prateleira-estudos { max-width: var(--measure); margin: 0 auto 2.2rem; padding: 0 1.1rem; }
/* ── O caderno recolhe  (08/09) ─────────────────────────────────────────────
   O cabeçalho do caderno é um `<summary>`: recolhido, o caderno é UMA linha
   e a prateleira vira a lista dos livros; expandido, as fichas descem. O
   triângulo e o marcador são os dos grupos da página de destaques. Recolhido,
   a margem encolhe — dez livros recolhidos têm de caber numa tela. */
.caderno:not([open]) { margin-bottom: .35rem; }
.caderno > summary, .prateleira-estudos > h2 {
  font-family: var(--sans); font-size: .78rem; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--tenue);
  margin: 0 0 .5rem; display: flex; align-items: baseline; gap: .5rem;
}
.caderno > summary {
  list-style: none; cursor: pointer; padding: .55rem 0;
  min-height: var(--alvo);
  border-bottom: 1px solid var(--regra);
  -webkit-tap-highlight-color: transparent;
}
.caderno > summary::-webkit-details-marker { display: none; }
.caderno > summary::before {
  content: "▸"; color: var(--tinta-2); font-size: .8em; align-self: center;
  transition: transform var(--dur-rapida) var(--curva);
}
.caderno[open] > summary::before { transform: rotate(90deg); }
.caderno[open] > summary { border-bottom-color: transparent; }
.caderno > summary:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; border-radius: 6px; }
/* O nome do caderno é o nome de um LIVRO: serifa, caixa normal — ele não é um
   rótulo de seção como «na mesa», é um título. */
.caderno > summary .nome {
  font-family: var(--corpo); font-size: 1.12rem; font-weight: 600;
  letter-spacing: 0; text-transform: none; color: var(--tinta);
}
.caderno > summary .conta, .prateleira-estudos > h2 .conta {
  margin-left: auto; white-space: nowrap; font-variant-numeric: tabular-nums;
  font-size: .74rem; color: var(--tenue); letter-spacing: 0; text-transform: none;
}
.fichas { list-style: none; margin: 0; padding: 0; }
/* A ENCADERNAÇÃO: um filete que atravessa os capítulos do mesmo livro. É o que
   uma pilha de capítulos tem e uma lista de avulsos não tem. */
.fichas.encadernadas { border-left: 2px solid var(--papel-borda); padding-left: .9rem; margin-left: .2rem; }

.ficha {
  position: relative; display: flex; align-items: stretch; gap: .6rem;
  background: var(--papel-elev); border: 1px solid var(--papel-borda-fina);
  border-radius: 14px; box-shadow: var(--sombra-erguida);
  margin-bottom: .8rem; overflow: hidden;
}
/* A lombada, na matiz do tema — a mesma do cartão da inbox: duas telas que
   mostram o mesmo acervo não podem discordar de cor. */
.ficha::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px; background: var(--t, var(--acento));
}
.ficha .alvo {
  flex: 1 1 auto; min-width: 0; display: block;
  padding: .9rem 1rem .9rem 1.1rem; text-decoration: none; color: inherit;
}
.ficha .tema {
  display: block; font-family: var(--sans); font-size: .7rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--t, var(--tenue));
  margin-bottom: .3rem;
}
.ficha .titulo {
  display: block; font-family: var(--corpo); font-size: 1.06rem; line-height: 1.3;
  color: var(--tinta); margin-bottom: .15rem;
}
.ficha .autor { display: block; font-family: var(--sans); font-size: .82rem; color: var(--tenue); }

/* ── A régua das partes ───────────────────────────────────────────────────
   Um traço por parte, e não uma barra contínua: o estudo não anda em
   porcentagem, anda em ETAPAS, e uma barra mentiria sobre a granularidade. */
.ficha .percurso { display: flex; align-items: center; gap: .6rem; margin-top: .7rem; }
.ficha .regua { display: flex; gap: 3px; flex: none; }
.ficha .regua i {
  display: block; width: 16px; height: 4px; border-radius: 2px;
  background: var(--regra);
}
.ficha .regua i.feita { background: var(--t, var(--acento)); }
.ficha .regua i.corrente { background: var(--acento); box-shadow: 0 0 0 2px var(--papel-elev), 0 0 0 3px var(--acento); }
.ficha .estado {
  font-family: var(--sans); font-size: .8rem; font-weight: 600; color: var(--acento);
}
.ficha.concluida .estado { color: var(--tenue); font-weight: 500; }

.ficha .acoes { flex: none; display: flex; align-items: center; gap: .3rem; padding-right: .8rem; }
.ficha .acoes .redondo { width: 29px; height: 29px; min-height: 0; font-size: .8rem; }
/* O caderno é o gesto DISCRETO da ficha: o ✕ apaga um estudo inteiro e este só
   muda o arco a que ele pertence. Sem contorno até o toque ou o foco. */
.ficha .acoes .caderno-de { border-color: transparent; background: transparent; color: var(--tenue); }
.ficha .acoes .caderno-de:hover, .ficha .acoes .caderno-de:focus-visible {
  border-color: var(--papel-borda); color: var(--tinta);
}
.ficha .aviso-estado {
  flex-basis: 100%; font-family: var(--sans); font-size: .8rem;
  color: var(--perigo); margin: 0; padding: 0 1rem .8rem 1.1rem;
}

/* ── Os painéis: da família do `#nota` ──────────────────────────────────── */
#respostas .enunciado, #calibrar .titulo, #ressonancia .titulo, #escrivaninha .titulo {
  font-family: var(--sans); font-weight: 600; font-size: 1rem; color: var(--tinta);
  margin: 0 0 .8rem; line-height: 1.4;
}
/* ── O miolo rola; a linha de botões fica  (L-81) ─────────────────────────
   O `.sheet` é uma coluna flexível com teto de altura, e sem um filho que
   role o excedente escapa da caixa: a correção de uma resposta aberta
   desenhava por cima da página e empurrava os botões para fora da tela. É a
   mesma regra dos turnos do `#conversa` e da lista do `⋯`. */
#respostas .corpo-resposta {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  /* Espaço para o anel de foco do campo e das alternativas, que é desenhado
     para fora da borda e seria cortado pelo `overflow`. */
  padding-inline: 2px; margin-inline: -2px;
}
/* O código e o negrito que o modelo escreve. `code` numa medida menor porque
   a fonte monoespaçada desenha maior no mesmo corpo — sem isto, `/wps` fica
   mais alto que a frase em volta. */
#respostas code {
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: .88em; background: var(--papel-elev-2); border-radius: 4px;
  padding: .05em .3em;
}
/* O termo em jogo, dentro do enunciado. O enunciado inteiro já é seminegrito,
   então um `<strong>` ali não se distingue de nada — na captura de 03/09 as
   duas palavras marcadas pelo modelo sumiam no meio da frase. O acento é a
   marca que este app usa para «é disto que se trata», e mede 8,69 : 1 no
   claro (8,43 sépia, 7,78 escuro) sobre o papel do painel. */
#respostas .enunciado strong { color: var(--acento); }
#respostas .passo-resposta {
  font-family: var(--sans); font-size: .74rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--tenue); margin: 0 0 .4rem;
}
/* ── A questão aberta de um quiz antigo  (spec 51 §7) ─────────────────────
   A caixa de texto saiu com a questão aberta. A que ficou gravada se LÊ: o que
   o leitor escreveu vai como citação, e a pendente diz que não se responde
   mais — sem campo e sem botão. */
#respostas .resposta-escrita {
  margin: 0; padding: .5rem .8rem; border-left: 3px solid var(--regra);
  font-family: var(--corpo); font-size: .96rem; line-height: 1.55; color: var(--tinta-2);
}
#respostas .questao-antiga { margin: 0; font-family: var(--sans); font-size: .88rem; color: var(--tenue); }
/* ── A tabela do «ler o dado» e o fundamento  (spec 54) ─────────────────────
   A tabela ROLA na horizontal dentro do painel: no telefone, cinco colunas
   não cabem, e a página não pode ganhar rolagem lateral por causa dela. */
#respostas .tabela-rola { overflow-x: auto; margin: .2rem 0 .6rem; }
/* O corpo é o das alternativas (.92rem, em rem): em `em` ela herdava o corpo
   da página e saía maior que o texto das opções — visto na captura de 16/09. */
#respostas .tabela-questao { border-collapse: collapse; font-family: var(--sans); font-size: .92rem;
  line-height: 1.35; min-width: 100%; font-variant-numeric: tabular-nums lining-nums; }
#respostas .tabela-questao th,
#respostas .tabela-questao td { padding: .3rem .6rem; border-bottom: 1px solid var(--regra); text-align: left; }
#respostas .tabela-questao th { color: var(--tinta); font-weight: 600; vertical-align: bottom; }
#respostas .fundamento { margin-top: .5rem; }
#respostas .alternativas { display: flex; flex-direction: column; gap: .4rem; }
#respostas .alternativa {
  text-align: left; font-family: var(--sans); font-size: .92rem; line-height: 1.45;
  padding: .6rem .7rem; border: 1px solid var(--regra); border-radius: 10px;
  background: var(--papel); color: var(--tinta); cursor: pointer;
}
#respostas .alternativa b { color: var(--acento); margin-right: .4rem; }
/* ── ORDENAR  (spec 51 §4.4) ──────────────────────────────────────────────
   Toque, não arraste: ↑ e ↓ em cada item, com 44px de alvo cada. Respondida, a
   borda diz se o item ficou no lugar (acento) ou fora dele (perigo), e a
   explicação do que ficou fora vem na devolutiva, embaixo. */
#respostas .ordenar { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .4rem; }
#respostas .item-ordenar {
  display: flex; align-items: center; gap: .5rem; padding: .2rem .25rem .2rem .7rem;
  border: 1px solid var(--regra); border-radius: 10px; background: var(--papel);
  font-family: var(--sans); font-size: .92rem; line-height: 1.45; color: var(--tinta);
}
#respostas .item-ordenar .pos { min-width: 1.1em; font-weight: 600; color: var(--acento); }
#respostas .item-ordenar .texto { flex: 1 1 auto; padding-block: .4rem; }
#respostas .item-ordenar .mover { display: flex; gap: .25rem; flex: 0 0 auto; }
#respostas .item-ordenar button {
  min-width: 44px; min-height: 44px; padding: 0;
  border: 1px solid var(--regra); border-radius: 8px; background: var(--papel-elev-2);
  color: var(--tinta); font-size: 1.05rem; cursor: pointer;
}
#respostas .item-ordenar button:disabled { opacity: .35; cursor: default; }
#respostas .item-ordenar[data-lugar="certo"] { border-color: var(--acento); }
#respostas .item-ordenar[data-lugar="errado"] { border-color: var(--perigo); }
#respostas .conferir { margin: .7rem 0 0; }
/* ── O descarte do verificador, e o `menos`  (spec 51 §4.3, §4.4) ─────────
   Uma linha que se abre: o número vem à vista, e o motivo de cada questão sob
   o toque. Tinta secundária, e não a do perigo: não é erro do leitor nem do
   app — é a régua funcionando. O `summary` é o alvo, com 44px. */
.descartadas {
  margin: 0 0 .8rem; padding: 0 .7rem; border: 1px solid var(--regra); border-radius: 10px;
  font-family: var(--sans); font-size: .86rem; color: var(--tinta-2); background: var(--papel);
}
.descartadas summary { min-height: 44px; display: flex; align-items: center; cursor: pointer; }
.descartadas ul { margin: 0 0 .6rem; padding-left: 1.1rem; }
.descartadas li + li { margin-top: .4rem; }
.descartadas .enunciado-descartado { display: block; color: var(--tinta); }
.descartadas .motivo { display: block; font-size: .82rem; }
/* O quiz que ficou vazio: o aviso mora na coluna do texto, abaixo da trilha. */
.quiz-vazio { max-width: 46rem; margin: 0 auto 1rem; padding-inline: 1rem; }
.quiz-vazio .sub { font-family: var(--sans); font-size: .9rem; color: var(--tinta-2); margin: 0 0 .6rem; }
#respostas .menos {
  margin: 0 0 .8rem; font-family: var(--sans); font-size: .86rem; color: var(--tinta-2);
}
#respostas .fora-de-lugar { margin: .5rem 0 0; padding-left: 1.1rem; font-size: .9rem; }
#respostas .fora-de-lugar li + li { margin-top: .3rem; }
#respostas .alternativa[data-escolhida="sim"] { border-color: var(--acento); }
#respostas .feedback {
  margin-top: .8rem; padding: .7rem .8rem; border-radius: 10px;
  background: var(--papel-elev-2); font-family: var(--corpo);
  font-size: .94rem; line-height: 1.55; color: var(--tinta);
}
/* A marca vive DENTRO do parágrafo (ver o `desenhar` do painel): inline, ela
   abre a primeira linha do texto em vez de ocupar uma linha só para si. */
#respostas .feedback .marca { font-size: 1.1rem; margin-right: .4rem; font-weight: 600; }
#respostas .feedback.rcerto .marca { color: var(--acento); }
#respostas .feedback.rerrado .marca { color: var(--perigo); }
#respostas .feedback p { margin: 0; }
/* A rubrica só aparece DEPOIS da resposta — antes dela, o servidor nem a
   manda (a projeção do §3.2). Esta regra desenha o que já chegou; não é ela
   que esconde. */
#respostas .feedback .rubrica {
  margin-top: .5rem; font-size: .86rem; color: var(--tinta-2);
}
#respostas .linha, #calibrar .botoes, #ressonancia .botoes, #escrivaninha .botoes {
  display: flex; align-items: center; gap: .5rem; margin-top: .9rem;
}
#respostas .linha .sub, #calibrar .botoes .sub, #ressonancia .botoes .sub {
  flex: 1 1 auto; font-size: .82rem; color: var(--tenue);
}

/* ── Calibrar e enviar ─────────────────────────────────────────────────── */
#calibrar .campo, #ressonancia .campo, #escrivaninha .opcao {
  display: block; font-family: var(--sans); font-size: .84rem; color: var(--tinta-2);
  margin-bottom: .8rem;
}
#calibrar select, #calibrar input[type="text"], #ressonancia input[type="text"],
#escrivaninha select, #escrivaninha input[type="text"] {
  display: block; width: 100%; margin-top: .3rem;
  font-family: var(--sans); font-size: .95rem; color: var(--tinta);
  background: var(--papel); border: 1px solid var(--regra); border-radius: 10px;
  padding: .5rem .6rem;
}
/* ── A lente do técnico  (spec 51 §2) ─────────────────────────────────────
   Duas opções com uma linha cada. A opção INTEIRA é o alvo (o `<label>`), com
   44px de piso: o círculo do rádio sozinho tem 13px e não se acerta com o
   dedo no iPad. A escolhida ganha a borda do acento — a mesma marca da
   alternativa escolhida no quiz. */
#calibrar fieldset.campo { border: 0; padding: 0; margin: 0 0 .8rem; min-width: 0; }
/* O `display: block` do `.campo` vence o `[hidden]` do navegador, e o campo
   que não se aplica ficava na tela: o técnico mostrava «Modo: Catequético»
   (visto na captura de 14/09), e mostraria a lente no filosófico. */
#calibrar .campo[hidden] { display: none; }
#calibrar fieldset.campo legend { padding: 0; margin-bottom: .3rem; }
#calibrar .lente {
  display: flex; align-items: flex-start; gap: .6rem; min-height: 44px;
  box-sizing: border-box; padding: .55rem .7rem; margin-top: .35rem;
  border: 1px solid var(--regra); border-radius: 10px; background: var(--papel);
  color: var(--tinta); cursor: pointer;
}
#calibrar .lente:has(input:checked) { border-color: var(--acento); }
#calibrar .lente input { margin: .2rem 0 0; accent-color: var(--acento); }
#calibrar .lente b { display: block; font-size: .95rem; font-weight: 600; }
#calibrar .lente .linha-lente { display: block; font-size: .84rem; color: var(--tinta-2); line-height: 1.4; }

/* ── A lista do combobox  (03/09) ────────────────────────────────────────
   Ela nasce e some conforme o que se digita, e por isso mora DENTRO do fluxo
   do painel, e não flutuando por cima: um menu absoluto sobre um sheet que já
   é `position: fixed` teria de repetir a conta de posição do pai a cada
   tecla — e erraria no iPad, onde o teclado muda a altura útil no meio da
   digitação. No fluxo, quem resolve é o navegador. */
#escrivaninha #caderno-lista {
  list-style: none; margin: .1rem 0 .6rem; padding: 0;
  max-height: 9rem; overflow-y: auto;
  border: 1px solid var(--regra); border-radius: 10px; background: var(--papel);
}
#escrivaninha #caderno-lista li {
  display: flex; align-items: center; justify-content: space-between; gap: .6rem;
  padding: .45rem .7rem; cursor: pointer;
  font-family: var(--sans); font-size: .92rem; color: var(--tinta);
}
#escrivaninha #caderno-lista li + li { border-top: 1px solid var(--papel-borda-fina); }
#escrivaninha #caderno-lista li:hover,
#escrivaninha #caderno-lista li[aria-selected="true"] { background: var(--papel-elev-2); }
#escrivaninha #caderno-lista .conta { font-size: .8rem; color: var(--tenue); }
/* A dica diz o que o «Enviar» VAI fazer — antes de ele fazer. É a diferença
   entre um campo que aceita qualquer coisa e um que declara a consequência. */
#escrivaninha #caderno-dica { min-height: 1.1em; }

#escrivaninha .opcao { display: flex; align-items: center; gap: .5rem; font-size: .95rem; color: var(--tinta); }
#escrivaninha .alvo { font-family: var(--corpo); color: var(--tinta-2); margin: 0 0 .9rem; }
#calibrar .dica, #escrivaninha .dica { font-size: .82rem; color: var(--tenue); margin: 0 0 .8rem; }
#escrivaninha .aviso { font-size: .84rem; color: var(--perigo); margin: .6rem 0 0; }
/* A primária é a exceção deliberada: ela veste o ACENTO do papel, em campo
   cheio, e é assim que se distingue das irmãs agora que as irmãs são grafite.
   Um sheet em que todos os botões são cromo não tem ação primária nenhuma. */
.btn.primario { background: var(--acento); color: var(--sobre-acento); border-color: transparent; font-weight: 600; }

/* ── Os callouts do estudo ─────────────────────────────────────────────────
   A pipeline da ingestão já converte `> [!important]` em
   `blockquote.callout.callout-important` (é o que a skill `enviar-leitor`
   produz há meses), e até aqui o app não os desenhava: a ideia-mestra de uma
   parte, que é o elemento de maior peso do estudo, saía como uma citação
   comum. Estas regras valem para TODO artigo do vault que use callout, e não
   só para o estudo — é a mesma marcação. */
.prosa blockquote.callout {
  border-left: 3px solid var(--acento);
  background: var(--papel-elev-2);
  padding: .8rem 1rem; border-radius: 0 10px 10px 0; margin: 1.4rem 0;
  font-style: normal;
}
.prosa blockquote.callout p:first-child { margin-top: 0; }
.prosa blockquote.callout p:last-child { margin-bottom: 0; }
/* ── `inline-block`, e NUNCA `block`  (05/09) ──────────────────────────────
   Este rótulo era `display: block`, e com isso o `::highlight()` da leitura
   falada **parava de pintar o parágrafo inteiro** no WebKit: um filho inline
   que vira bloco parte o `<p>` em blocos anônimos, e o realce da frase e o da
   palavra somem de tudo que vem depois. O dono leu a caixa inteira com a voz
   e sem marca nenhuma — «depois que saiu da caixa funcionou normal».

   Nada no DOM denuncia: o `Highlight` fica registrado, os ranges resolvem, o
   seletor casa. O observável é o pixel, e é o que `npm run design` mede agora.

   `inline-block` com `width: 100%` dá a MESMA quebra de linha e mantém o
   `margin-bottom` (que um inline puro ignoraria), sem partir o parágrafo: o
   átomo inline não cria bloco anônimo. Vale para qualquer filho inline da
   `.prosa` — dentro de texto que se narra, `display: block` é proibido. */
.prosa blockquote.callout strong:first-child {
  font-family: var(--sans); font-size: .78rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--acento);
  display: inline-block; width: 100%; margin-bottom: .3rem;
}
/* A passagem verbatim é a única que continua parecendo CITAÇÃO: ela é a voz do
   texto original dentro do estudo, e igualá-la à ideia-mestra apagaria a
   diferença entre o que o autor disse e o que o tutor concluiu. */
.prosa blockquote.callout-quote {
  border-left-color: var(--regra); background: none;
  font-family: var(--corpo); font-style: italic;
}
/* `--tinta`, e não uma tinta secundária: este rótulo vive DENTRO da `.prosa`,
   que é destacável, e os quatro `--hl-*` foram calibrados contra `--tinta`
   (nucleo.test). Quem separa o micro-contexto do corpo da citação é o tamanho
   e o espacejamento, não a cor — que é o que a regra da prosa obriga. */
.prosa blockquote.callout-quote strong:first-child { color: var(--tinta); font-style: normal; opacity: .75; }

/* ── Os desenhos do arquiteto: trade-off e quadro de falhas  (spec 51 §3.4) ──
   O servidor os entrega como tabela DENTRO de um callout (`recursos.mjs`),
   porque `callout-*` é a única classe que o sanitizador deixa o conteúdo
   carregar. Só tokens: é o que os faz valer nos três temas sem uma regra por
   tema. A borda do acento vira regra neutra no trade-off — ele não é a
   ideia-mestra, e duas caixas com a mesma marca disputariam a atenção —, e o
   quadro de falhas leva a cor do perigo, que é do que ele fala. */
.prosa blockquote.callout-tradeoff,
.prosa blockquote.callout-falhas { border-left-color: var(--regra); padding-bottom: .5rem; }
.prosa blockquote.callout-falhas { border-left-color: var(--perigo); }
.prosa blockquote.callout-tradeoff table,
.prosa blockquote.callout-falhas table { margin: .2rem 0 0; font-family: var(--sans); font-size: .88em; }
/* A primeira coluna é o NOME (a opção, a falha): é por ela que a linha se lê. */
.prosa blockquote.callout-tradeoff td:first-child,
.prosa blockquote.callout-falhas td:first-child { font-weight: 600; color: var(--tinta); }
/* Nas células do trade-off cabe uma palavra ou um sinal: centradas, a coluna
   se compara de relance, que é para o que a grade existe. */
.prosa blockquote.callout-tradeoff th:not(:first-child),
.prosa blockquote.callout-tradeoff td:not(:first-child) { text-align: center; }
.prosa blockquote.callout-tradeoff tr:last-child td,
.prosa blockquote.callout-falhas tr:last-child td { border-bottom: 0; }

/* ── A espinha da parte do arquiteto  (spec 51 §3.2) ──────────────────────
   problema → forças → (as seções) → alternativas → premissas → limite. Cada
   elo é um callout com classe própria (`montar.mjs`), e a folha os distingue
   só por borda, com tokens: o problema e as premissas são contexto (regra
   neutra), as forças são o miolo da decisão (o acento, como a ideia-mestra), e
   o limite é onde o desenho quebra — a cor do perigo, como o quadro de falhas.
   A lista dentro do callout perde a margem de cima: o título já separa. */
.prosa blockquote.callout-problema,
.prosa blockquote.callout-premissas { border-left-color: var(--regra); }
.prosa blockquote.callout-forcas { border-left-color: var(--acento); }
.prosa blockquote.callout-limite { border-left-color: var(--perigo); }

/* ── As caixas do Concurso  (spec 54 §2.2) ──────────────────────────────────
   «Cai assim» é o que a banca cobra: o acento, como a ideia-mestra. A
   «pegadinha» é onde a banca derruba: a cor do perigo, como o limite do
   arquiteto. Só a borda muda; o corpo é o de todo callout. */
.prosa blockquote.callout-cai { border-left-color: var(--acento); }
.prosa blockquote.callout-pegadinha { border-left-color: var(--perigo); }
/* O nome da força (e de qualquer item em negrito numa lista de callout) é o
   PRIMEIRO `strong` do `li`, e a regra do rótulo acima o pegava: caixa alta, no
   acento e em bloco, com a linha da força solta embaixo — visto na captura de
   14/09. Dentro de `li` o negrito volta a ser negrito de texto. `inline`, e
   não `block`: dentro da prosa narrada, bloco apaga o realce da voz. */
.prosa blockquote.callout li strong:first-child {
  display: inline; width: auto; margin: 0; font-family: inherit; font-size: inherit;
  letter-spacing: normal; text-transform: none; color: var(--tinta);
}
.prosa blockquote.callout-forcas ul,
.prosa blockquote.callout-premissas ul { margin-top: .2rem; margin-bottom: 0; }

/* ── «Há uma versão nova»  (03/09) ─────────────────────────────────────────
   No pé, e não no topo: o topo é onde o título do que se lê mora, e uma tarja
   ali empurra a primeira linha do texto. Acima da barra de navegação do modo
   estreito, para não cobrir os destinos. */
/* ── Refeita em UMA linha, centrada sem `left: 50%`  (17/09) ───────────────
   A de 04/09 quebrava em duas linhas e o Yuri a achou feia em todo lugar, pior
   no iPhone. O defeito de fundo não era a frase: era `left: 50%` com
   `translateX(-50%)`. Uma caixa fixa sem largura declarada encolhe até caber
   no espaço entre o `left` e a borda direita — METADE da tela. Num iPhone de
   393px ela media 200px, e o `flex-wrap` de 04/09 só escolheu onde quebrar.

   Agora: `left: 0; right: 0; margin-inline: auto` com `width: fit-content`
   centra usando a tela inteira como limite; frase curta, sem quebra; pílula de
   verdade (é sempre uma linha); o ✕ é um ícone sem cromo, e não um quadrado
   escuro de gradiente, que no sépia parecia uma tecla solta. Os dois alvos
   continuam com os 44px do `--alvo`. Se a tela for estreita demais (320px), a
   frase cede com reticências antes de os botões cederem. */
#versao-nova {
  position: fixed; z-index: 80;
  left: 0; right: 0; margin-inline: auto;
  width: fit-content; max-width: calc(100% - 2rem); box-sizing: border-box;
  bottom: calc(var(--barra-h, 0px) + 1rem + env(safe-area-inset-bottom));
  display: flex; align-items: center; flex-wrap: nowrap; gap: .35rem;
  padding: 4px 4px 4px 1.1rem; border-radius: 999px;
  background: var(--papel-elev); border: 1px solid var(--regra);
  box-shadow: 0 1px 2px rgba(0,0,0,.08), 0 10px 30px rgba(0,0,0,.18);
  font-family: var(--sans); font-size: .88rem; color: var(--tinta);
}
#versao-nova > span {
  flex: 0 1 auto; min-width: 0; margin-right: .4rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#versao-nova > button {
  flex: none; height: var(--alvo, 44px); border: 0; border-radius: 999px;
  font: inherit; cursor: pointer;
}
#versao-nova #versao-recarregar {
  padding: 0 1.1rem;
  background: var(--acento); color: var(--sobre-acento); font-weight: 600;
}
#versao-nova #versao-depois {
  width: var(--alvo, 44px); padding: 0;
  display: grid; place-items: center;
  background: transparent; color: var(--tenue);
}
#versao-nova #versao-recarregar:hover { filter: brightness(1.06); }
#versao-nova #versao-depois:hover { color: var(--tinta); background: color-mix(in srgb, var(--tinta) 8%, transparent); }
#versao-nova > button:focus-visible { outline: 2px solid var(--acento); outline-offset: 2px; }
/* Lendo no telefone há DUAS barras no pé: a de abas e, acima dela, a fileira
   de controles da leitura. Pousada só acima da primeira, a tarja cobria a
   segunda inteira — o ⏸, o Aa e o progresso sumiam debaixo dela. Visto no
   Safari do iPhone simulado em 17/09; o Chrome emulado não montava a cena.
   `--pilha-y` já é a soma das duas no arranjo em barra. */
body[data-leitura][data-arranjo="barra"] #versao-nova {
  bottom: calc(var(--pilha-y) + .75rem);
}
@media (min-width: 1100px) and (pointer: fine) {
  /* No Mac a navegação é lateral: a tarja desce para o canto e não disputa o
     centro com a coluna de leitura. */
  #versao-nova { left: auto; right: 1.2rem; margin-inline: 0; bottom: 1.2rem; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   A ESCRIVANINHA — os três blocos que não chegaram a existir  (03/09)
   ═══════════════════════════════════════════════════════════════════════════
   Eles foram escritos e a edição do arquivo não casou o ponto de inserção; o
   resultado, no Mac, foi o painel do «Mais» desenhado pelo NAVEGADOR: bolinhas
   de lista ao lado dos botões, nome e descrição correndo na mesma linha
   («RecomeçarApaga as suas respostas…») e tudo centrado.

   Ficam guardados por teste (`estudo.test.mjs`): uma folha de estilo em que
   uma regra some não falha em lugar nenhum — ela só fica feia, e feio não
   quebra build.
   ═════════════════════════════════════════════════════════════════════════ */

/* ── A antessala: o fundo das etapas que não são documento ────────────────── */
.antessala h1 {
  font-family: var(--corpo); font-size: 1.6rem; line-height: 1.25; margin: 0 0 .3rem;
}
.antessala .autor {
  font-family: var(--sans); font-size: .88rem; color: var(--tenue); margin: 0 0 .8rem;
}
.antessala .sub {
  font-family: var(--sans); font-size: .95rem; color: var(--tinta-2); margin: 0;
}

/* ── O rodapé de uma ETAPA de estudo ──────────────────────────────────────
   Ela é um `ART#` como outro (é o que lhe dá narração e Pencil), mas não é item
   do acervo: não se marca como lida, não vai para a estante e não se manda
   estudar. Fica o que se aplica — de onde veio e para onde voltar. */
.rodape-etapa .procedencia {
  font-family: var(--sans); font-size: .86rem; color: var(--tinta-2);
}

/* ── O «Mais» do estudo: três gestos que apagam coisas diferentes ─────────
   Cada opção diz o que leva junto ANTES da confirmação — é a spec 23 §7 na
   tela, e a razão de eles serem três botões e não um item de menu.

   `list-style: none` não é higiene: sem ele o navegador desenha marcadores ao
   lado de botões. E `<b>`/`<span>` precisam de `display: block`, senão o nome
   e a descrição correm na mesma linha. */
/* ── Quem rola é a LISTA, não o painel — a regra L-81, aplicada aqui ───────
   O painel é uma coluna flexível com teto de altura (`.sheet`, lá em cima), e
   sem `flex`/`overflow` na lista o excedente empurrava a linha do «Cancelar»
   para FORA da caixa: em 03/09 o menu passou de três para cinco opções e a
   captura mostrou o botão pendurado no vazio, por cima da tela de trás.
   Controle que sai do painel é controle que não existe — a mesma frase que o
   `#conversa` já carregava. */
.opcoes-estudo {
  list-style: none; margin: 0 0 .2rem; padding: 0;
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  /* Os 2px seguram o anel de foco do botão, que é desenhado para fora da
     borda e seria cortado pelo `overflow`. */
  padding-inline: 2px; margin-inline: -2px;
}
.opcoes-estudo li { margin: 0 0 .45rem; }
.opcoes-estudo button {
  display: block; width: 100%; text-align: left; cursor: pointer;
  padding: .75rem .85rem;
  background: var(--papel); border: 1px solid var(--regra); border-radius: 12px;
  font-family: var(--sans); color: var(--tinta);
}
.opcoes-estudo button:hover, .opcoes-estudo button:focus-visible {
  border-color: var(--acento); outline: none;
}
.opcoes-estudo b {
  display: block; font-size: .96rem; font-weight: 600; margin-bottom: .2rem; line-height: 1.3;
}
.opcoes-estudo span {
  display: block; font-size: .84rem; line-height: 1.5; color: var(--tinta-2);
}
.opcoes-estudo .perigo b { color: var(--perigo); }
.opcoes-estudo .perigo:hover, .opcoes-estudo .perigo:focus-visible { border-color: var(--perigo); }
/* O título do painel na serifa, como o dos irmãos: é o nome da coisa, não um
   rótulo de controle. */
#mais-estudo .titulo { font-family: var(--corpo); font-size: 1.15rem; }

/* ── A trilha dentro do `⋯`  (14/09) ───────────────────────────────────────
   A do documento mora no alto dele, e alcançá-la do meio da leitura custava
   subir a página inteira — e gravar o topo como a posição da parte. Aqui ela
   é a MESMA marcação (`montarTrilha`), com as duas marcas de sempre, e só
   muda de tamanho: no alto do texto a pastilha é legenda de 22 px; num painel
   que se abre para tocar, ela é alvo, e alvo tem o `--alvo` do núcleo.
   `max-width`/`margin`/`padding` desfeitos porque os da trilha centram uma
   coluna de leitura, e aqui a coluna é o painel. */
#mais-estudo .ir-para .trilha { max-width: none; margin: .1rem 0 .9rem; padding: 0; }
#mais-estudo .ir-para .trilha ol { font-size: .9rem; gap: .45rem; }
#mais-estudo .ir-para .trilha .passo > button,
#mais-estudo .ir-para .trilha .passo > span {
  min-height: var(--alvo); min-width: var(--alvo); padding: 0 .85rem;
  display: flex; align-items: center; justify-content: center;
}

/* ── A linha dos dois toques do compartilhar  (spec 25 §5.4) ───────────────
   O painel troca a lista por UMA linha — «Montando o estudo… 3 de 7», depois
   «Estudo pronto · 24 KB» com o botão ao lado, ou o motivo da falha. Não é um
   painel novo: é o mesmo `#mais-estudo` com outro conteúdo, porque o gesto
   começou nele e o segundo toque é a continuação do primeiro.

   `min-height` de uma linha para o painel não pular de altura entre as três
   mensagens — o botão «Compartilhar» ficaria dançando sob o dedo. */
#mais-estudo .passo-linha {
  font-family: var(--sans); font-size: .92rem; color: var(--tinta-2);
  margin: .8rem 0 1.2rem; min-height: 1.4em;
}

/* ══ O COLÓQUIO — a conversa falada  (spec 24 §6.1) ═════════════════════════

   Faixa BAIXA, e é isso que faz o recurso: o artigo continua visível e
   rolável atrás, e dá para apontar o parágrafo com o olho enquanto se fala
   dele. Um `.sheet` cheio devolveria o defeito que a bolha flutuante existiu
   para consertar — conversar sobre um texto que não se vê.

   Ancorado como o `#velocidade-painel`: à esquerda da cápsula, pelos mesmos
   tokens de geometria, para que mexer na cápsula mova o painel junto em vez
   de abrir uma segunda conta que precisa concordar com a primeira. */
#coloquio {
  position: fixed; z-index: 60;
  right: calc(var(--capsula-x) + var(--capsula-l) + .6rem);
  /* ── `--pilha-0`, e NÃO `--pilha-y`  (correção da captura, 04/09) ─────────
     A primeira versão usava `--pilha-y`, como o `#velocidade-painel` faz — e
     no Mac isso é o CENTRO da tela, porque a cápsula se centra ali (a regra do
     `@media` acima). A captura mostrou o painel pousado em cima do parágrafo
     que se estava lendo, que é precisamente o defeito que a faixa baixa existe
     para não ter.
     E não é acaso: a linha de leitura desta casa É o meio da tela — é o que
     `segmentosDaLeitura()` mede, pela razão de que «ninguém lê no topo». Um
     painel ancorado no centro cobre exatamente onde o olho está.
     `--pilha-0` é o token que diz «acima do cromo de baixo»: a barra de
     navegação e a pílula do tempo, no modo barra. É o piso certo nos dois
     modos. Anexar a bolha era o instinto; o chão é o requisito. */
  bottom: var(--pilha-0);
  width: min(30rem, calc(100vw - var(--capsula-x) * 2 - var(--capsula-l) - 1.2rem));
  display: flex; flex-direction: column; gap: .5rem;
  padding: .7rem .9rem;
  background: var(--papel-elev); border: 1px solid var(--papel-borda);
  border-radius: var(--raio); box-shadow: var(--sombra-erguida);
  font-family: var(--sans);
  transition: opacity var(--dur) var(--curva), transform var(--dur) var(--curva);
}
/* `visibility`, e não só `opacity`, pelo motivo do `#velocidade-painel`: um
   painel transparente continua sendo parada de teclado e continua sendo lido
   pelo VoiceOver. */
#coloquio[data-aberto="nao"] {
  opacity: 0; visibility: hidden; pointer-events: none; transform: translateX(.5rem);
}

#coloquio .col-cabeca {
  display: flex; align-items: center; gap: .5rem;
}
#coloquio .col-quem {
  font-size: 13px; color: var(--tinta-fraca); flex: 1 1 auto;
}
/* Tabular: o relógio anda a cada segundo, e um dígito de largura variável faz
   a linha inteira tremer — o mesmo motivo do contador da escrivaninha. */
#coloquio .col-tempo {
  font-size: 13px; color: var(--tinta-fraca);
  font-variant-numeric: tabular-nums;
}
#coloquio .btn { flex: 0 0 auto; }

/* A luz é o único mostrador de estado que se lê sem ler. Três cores para três
   coisas, e nenhuma delas é vermelha: vermelho aqui seria confundido com
   gravação, e não se está gravando áudio nenhum (§11). */
#coloquio .col-luz {
  width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
  background: var(--tinta-fraca);
}
#coloquio .col-luz[data-quem="ouvindo"] { background: var(--foco); }
#coloquio .col-luz[data-quem="falando"] { background: var(--foco); opacity: .55; }
#coloquio .col-luz[data-quem="conectando"],
#coloquio .col-luz[data-quem="pensando"],
#coloquio .col-luz[data-quem="encerrando"] { background: var(--tinta-fraca); opacity: .6; }

#coloquio .col-retomada {
  font-size: 12px; color: var(--tinta-fraca);
}
#coloquio .col-retomada[hidden] { display: none; }

/* Três linhas à vista, e não a conversa inteira: isto é conferência — «ela
   entendeu o que eu disse?» —, não histórico. O histórico está gravado. */
#coloquio .col-fala {
  max-height: 7.5rem; overflow-y: auto;
  font-size: 14px; line-height: 1.45;
  border-top: 1px solid var(--regra); padding-top: .5rem;
}
#coloquio .col-linha { margin: 0 0 .4rem; }
#coloquio .col-linha:last-child { margin-bottom: 0; }
#coloquio .col-papel {
  display: inline-block; margin-right: .35rem;
  font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--tinta-fraca);
}
#coloquio .col-linha[data-papel="leitor"] { color: var(--tinta-fraca); }
/* A busca não é fala: é uma MARCA DE PROCEDÊNCIA. Ela se distingue das duas
   vozes porque a pergunta que responde é outra — «isto veio de onde?» — e a
   resposta a essa pergunta é o que sustenta o senso crítico de quem ouve. */
#coloquio .col-linha[data-papel="busca"],
#coloquio .col-linha[data-papel="busca-falhou"] {
  color: var(--tinta-fraca); font-style: italic;
}
#coloquio .col-linha[data-papel="busca"] .col-papel,
#coloquio .col-linha[data-papel="busca-falhou"] .col-papel { color: var(--foco); }
#coloquio .col-vazio { margin: 0; font-size: 13px; color: var(--tinta-fraca); }

/* O aviso NÃO se esconde num cinza discreto: ele existe porque alguma coisa
   não aconteceu, e a lição de 03/09 é que um braço mudo trava quem chamou. */
#coloquio .col-aviso {
  font-size: 13px; line-height: 1.4;
  border-top: 1px solid var(--regra); padding-top: .5rem;
  color: var(--foco);
}
#coloquio .col-aviso[data-tom="nota"] { color: var(--tinta-fraca); }
#coloquio .col-aviso[hidden] { display: none; }

/* ── A transcrição arquivada ───────────────────────────────────────────────
   `.sheet` inteiro, e não faixa: aqui não há sessão viva atrás, e o que se
   quer é ler. */
#transcricao .trans-titulo {
  margin: 0 0 .6rem; font-weight: 600; font-size: 15px;
}
#transcricao .trans-corpo {
  flex: 1 1 auto; overflow-y: auto; min-height: 0;
  font-size: 15px; line-height: 1.6;
}
#transcricao .trans-corpo p { margin: 0 0 .7rem; }
#transcricao .trans-corpo p:last-child { margin-bottom: 0; }

/* ── O status não cabe na linha dos botões  (correção da captura, 04/09) ────
   A `.linha` do `#nota` é `space-between` com um `.sub` curto de um lado
   («pensando…») e os botões do outro. O status daqui é uma FRASE —
   «transcrição crua — a arrumação não completou» —, e na captura ela corria
   por baixo do «Arrumar» e era cortada no meio: o leitor via «a arrumação não
   completou» virar «a arrumação não comple».
   Envolver e dar base larga ao status faz a frase descer para a própria linha
   quando não couber ao lado, e ficar ao lado quando couber (é o caso do
   status vazio, que é o comum). `min-width: 0` porque item de flex não encolhe
   abaixo do conteúdo sem ele — é o que fazia a frase transbordar em vez de
   quebrar. */
/* Não há `.linha` genérica no arquivo — cada sheet declara a sua (`#nota`,
   `#conversa`, `#colar`, `#metadados`). A do `#transcricao` não existia, e por
   isso o `flex-wrap` da primeira tentativa não teve em que pegar. */
#transcricao .linha {
  display: flex; align-items: center; flex-wrap: wrap;
  justify-content: flex-end; gap: .5rem; margin-top: .8rem;
}
#transcricao #trans-status { flex: 1 1 16rem; min-width: 0; line-height: 1.35; text-align: left; }

/* ─────────────────────────────────────────────────────────────────────────────
   O desenho e o destaque de sintaxe  (spec 37 §3.5, §3.6)

   O diagrama vive DENTRO do `<pre>` que o trouxe — é ele que carrega o
   `data-bid`, e o bid é o endereço do bloco para o progresso, a busca e o
   sumário. Trocar o elemento apagaria o endereço; trocar o conteúdo, não.
   ───────────────────────────────────────────────────────────────────────── */

.prosa pre.diagrama {
  background: none;
  /* A faixa de cima é do BOTÃO, e por isso ela existe: na captura de 07/09 o
     botão pousava em cima da caixa do último participante do sequenceDiagram.
     Um controle que encobre justamente o que ele serve para mostrar é pior
     que a falta dele.

     3.2rem porque o botão mede 44px de verdade — `min-height: var(--alvo)`
     do núcleo vence qualquer `height` menor, armadilha que esta folha já
     registrou duas vezes (o `#colar` que virou oval, o `.redondo` que virou
     elipse). A primeira tentativa reservou 2.3rem para um botão que eu
     achava de 34px, e a conferência de sobreposição pegou os 10px que
     faltavam. */
  padding: 3.2rem 0 .5em;
  overflow-x: auto;
  text-align: center;
  position: relative;
}
.prosa pre.diagrama svg { max-width: 100%; height: auto; }

/* ── A porta para a lente  (07/09) ───────────────────────────────────────────
   «Alguns diagramas ficam muito pequenos… tem como abrir ele grandão na
   tela?» O `max-width: 100%` acima está certo — um diagrama que estoura a
   medida do texto quebra a página —, e o preço dele é um `sequenceDiagram` de
   quatro participantes com rótulos de 5px. O botão é a saída.

   O glifo é conteúdo GERADO, como o número da linha: `content:` não entra no
   `textContent` do bloco, não é selecionável e não viaja na cópia. Um `⤢`
   escrito como texto entraria na coordenada dos destaques e na área de
   transferência de quem leva o exemplo para rodar.

   Duas coisas que a folha NÃO deixa fazer aqui, e as duas por bons motivos.
   Nada de `opacity` — a lição de 03/09: uma opacidade deitada sobre tinta já
   esmaecida mediu 2,30:1 no rótulo que se encarava por dois minutos. E nada
   de tinta secundária: `nucleo.test.mjs` proíbe `--tenue` e `--tinta-2`
   dentro de `.prosa`, porque um `--hl-*` pode nascer por baixo e os quatro
   destaques foram calibrados para `--tinta`. Escrevi `--tenue` aqui e o
   guarda pegou.

   Então a discrição vem da MEDIDA e da moldura — 34px num canto, com o campo
   da cerca por trás —, e não do apagamento da tinta. E no iPad, que é onde
   se lê, não existe `hover`: um botão que só aparece ao passar o mouse é um
   botão que não existe. */
/* ─────────────────────────────────────────────────────────────────────────────
   O botão de copiar a cerca  (07/09)

   Ele mora num wrapper `.cerca` e não dentro do `<pre>`: o `data-bid` está no
   `<pre>`, e o `textContent` dele é a coordenada de todo destaque, o que a
   busca varre e o que a voz narra. Um nó a mais lá dentro moveria traços já
   feitos — a razão de o número de linha ter de ser conteúdo gerado.

   O wrapper também tira o botão do alcance do pintor de destaques, que
   fotografa o miolo dos elementos com `data-bid` e devolve ao retrato o que
   mudou.
   ────────────────────────────────────────────────────────────────────────── */
/* Uma GRADE de uma célula, e não um contexto de posicionamento.
   `position: relative` aqui tornaria a cerca o `offsetParent` do `<pre>`, e a
   marginália mede a altura de cada nota com `offsetTop` — da marca ou do
   bloco —, contado a partir do ancestral posicionado, que o CSS fixa no
   `<main>`. Toda nota ancorada dentro de um bloco de código subiria para o
   topo da página. Medido no Safari: com `relative`, o `offsetTop` do bloco cai
   de centenas de pixels para ZERO. `display: grid` não mexe em
   `offsetParent`, e o botão se põe com `justify-self`. */
.prosa .cerca {
  display: grid;
  /* A grade abre um contexto de formatação próprio, então a margem do `<pre>`
     deixaria de colapsar com a dos vizinhos e o espaçamento da página mudaria.
     A margem sobe para o wrapper, e o bloco fica sem a sua. */
  margin: 1em 0;
}
.prosa .cerca > pre, .prosa .cerca > button.copiar { grid-area: 1 / 1; }
/* A faixa que o `<pre>` cede ao botão. Sem ela a primeira linha do programa
   corre por baixo do alvo de 44px — o defeito que a lente teve em 07/09, e que
   nenhum teste de CSS vê: quem o pega é a conferência de sobreposição. */
.prosa .cerca > pre {
  padding-right: 3.4rem;
  margin: 0;
}
.prosa .cerca > button.copiar {
  justify-self: end; align-self: start;
  margin: .2rem;
  /* 44 nos dois eixos, como o da lente: o núcleo impõe `min-height:
     var(--alvo)` a todo `button`, e uma altura menor só produz um retângulo. */
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 1px solid var(--borda-controle); border-radius: 8px;
  background: var(--papel-elev);
  color: var(--tinta);
  cursor: pointer;
  transition: color .15s ease, border-color .15s ease;
  -webkit-tap-highlight-color: transparent;
}
.prosa .cerca > button.copiar svg { width: 17px; height: 17px; grid-area: 1 / 1; }
/* Quem troca o desenho é o ESTADO, e não o DOM: os dois nascem no botão e a
   folha mostra um de cada vez. */
.prosa .cerca > button.copiar .ic-copiado { display: none; }
.prosa .cerca > button.copiar[data-estado="copiado"] { color: var(--foco); border-color: var(--foco); }
.prosa .cerca > button.copiar[data-estado="copiado"] .ic-copiar { display: none; }
.prosa .cerca > button.copiar[data-estado="copiado"] .ic-copiado { display: block; }
/* A falha aparece — sucesso mudo aqui é o leitor colando o que estava antes. */
.prosa .cerca > button.copiar[data-estado="falhou"] { color: var(--perigo); border-color: currentColor; }
@media (hover: hover) {
  .prosa .cerca > button.copiar:hover { color: var(--foco); border-color: var(--foco); }
}
.prosa .cerca > button.copiar:focus-visible {
  outline: 2px solid var(--foco); outline-offset: 2px;
}

/* ──────────────────────────────────────────────────────────────────────────
   A bancada  (spec 39 §3.4)

   O ▶ é o terceiro filho da grade da cerca, à esquerda do copiar e com os
   mesmos 44 px; a saída é a segunda LINHA da grade. `.com-rodar` marca a
   cerca que é célula do lab — só ela cede a faixa dupla ao `<pre>`; a cerca
   comum continua cedendo só a do copiar. A barra é `sticky` no pé do artigo:
   «Parar» tem de estar à mão enquanto a célula lá em cima roda.
   ────────────────────────────────────────────────────────────────────────── */
.prosa .cerca.com-rodar > pre { padding-right: calc(3.4rem + 44px + .4rem); }
.prosa .cerca > button.rodar {
  grid-area: 1 / 1;
  justify-self: end; align-self: start;
  margin: .2rem calc(.2rem + 44px + .4rem) 0 0;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 1px solid var(--borda-controle); border-radius: 8px;
  background: var(--papel-elev);
  color: var(--foco);
  cursor: pointer;
  transition: color .15s ease, border-color .15s ease;
  -webkit-tap-highlight-color: transparent;
}
.prosa .cerca > button.rodar svg { width: 18px; height: 18px; }
.prosa .cerca > button.rodar[data-estado="rodando"] { color: var(--tinta-suave, var(--tinta)); border-color: var(--foco); }
.prosa .cerca > button.rodar[data-estado="ok"] { border-color: var(--foco); background: var(--foco); color: var(--papel); }
.prosa .cerca > button.rodar[data-estado="erro"] { color: var(--perigo); border-color: currentColor; }
.prosa .cerca > button.rodar:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* A saída: segunda linha da grade, colada à cerca. */
.prosa .cerca > .saida {
  grid-row: 2; grid-column: 1;
  margin: 0;
  padding: .55rem .9rem .65rem;
  border: 1px solid var(--borda-controle); border-top: 0;
  border-radius: 0 0 6px 6px;
  background: var(--papel);
  font-family: var(--mono); font-size: .82em; line-height: 1.5;
  color: var(--tinta);
  position: relative;
}
.prosa .cerca > .saida[data-antiga] { opacity: .55; }
.prosa .cerca > .saida[data-n]:not([data-n=""])::before {
  content: "[" attr(data-n) "]";
  display: block;
  font-size: .8em; opacity: .6;
  margin-bottom: .25rem;
}
.prosa .cerca > .saida pre {
  margin: 0; padding: 0;
  background: none; border: 0; border-radius: 0;
  font-size: inherit; line-height: inherit;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.prosa .cerca > .saida pre + pre { margin-top: .35rem; }
.prosa .cerca > .saida pre.g-resultado { border-left: 3px solid var(--foco); padding-left: .6rem; }
.prosa .cerca > .saida pre.g-stderr, .prosa .cerca > .saida pre.g-erro { color: var(--perigo); }
.prosa .cerca > .saida p.g-corte { margin: .35rem 0 0; font-style: italic; opacity: .7; }
/* `width: auto` DECLARADO, e é ele que faz o `max-width` acima valer alguma
   coisa: a figura da ilustração do artigo é `.prosa img { width: 100% }` (lá em
   cima), e essa largura descia até aqui — a regra mais específica trocava o
   `max-width` e deixava o `width` de pé. Uma figura de matplotlib de 534px
   esticada para os 742 da coluna é 39% de ampliação num raster com eixo e
   rótulo dentro: fica borrada, e nada avisa. Ilustração de artigo preenche a
   coluna porque é decisão de página; saída de célula tem o tamanho que o
   kernel desenhou. Medido no Safari em 09/09, pelo `npm run bancada`. */
.prosa .cerca > .saida img { display: block; width: auto; max-width: 100%; height: auto; margin-top: .5rem; }

/* ── A saída de REFERÊNCIA e a célula que não passou  (spec 43 §6.3-6.4) ──
   A referência é a saída que o gate MEDIU quando escreveu a etapa, e ela vem
   no próprio markdown. Enquanto a célula não roda neste aparelho, ela é a
   melhor resposta que há para «o que sai daqui?» — esmaecida, porque é de
   outra máquina e de outro dia. Quando a saída local chega, ela some: duas
   respostas para a mesma pergunta, uma sob a outra, é o leitor comparando o
   que acabou de rodar com um fantasma.

   A célula que não passou na conferência não tem ▶ (o dado decide, em
   `bancada.mjs`), e a cerca diz isso na borda: o motivo já está escrito acima
   dela, em prosa, e a marca é só para o olho achar. */
.prosa .saida[data-origem="referencia"] { opacity: .62; }
.prosa .saida[data-origem="referencia"] p { font-size: .82em; }
.prosa .cerca.nao-conferida { border-left: 3px solid var(--perigo); padding-left: .5rem; }
.prosa .cerca.nao-conferida > pre { opacity: .8; }

/* ──────────────────────────────────────────────────────────────────────────
   O modo Editar  (spec 43 §7.2)

   O campo ocupa a MESMA célula da grade que o `<pre>` — `1 / 1` —, e o `pre`
   sai por `hidden`. Duas versões do mesmo código na tela, uma sobre a outra,
   seria a pior leitura possível de um lab.

   A medida do texto é a do `<pre>` para que ligar o modo não reflua a página:
   a mesma família, o mesmo corpo e a mesma entrelinha. E a faixa da direita é
   a mesma que o `<pre>` cede — o ▶ e o copiar continuam onde estavam, e o
   programa não corre por baixo deles.
   ────────────────────────────────────────────────────────────────────────── */
.prosa .cerca > textarea.celula-editor {
  grid-area: 1 / 1;
  width: 100%;
  box-sizing: border-box;
  margin: 0;
  padding: .55rem 3.4rem .65rem .9rem;
  border: 1px solid var(--foco);
  border-radius: 6px;
  background: var(--papel-elev);
  color: var(--tinta);
  font-family: var(--mono); font-size: .86em; line-height: 1.55;
  /* O campo é CÓDIGO, e o `<pre>` que ele cobre não quebra linha nenhuma: um
     textarea que quebra faz a linha longa mudar de forma ao ligar o modo, e a
     coluna 80 cair no meio da tela. `pre` (com o `wrap="off"` que o módulo
     põe no elemento) rola na horizontal, como a cerca ao lado.

     `hyphens`/`word-break` vêm da PROSA, que é o pai: a folha hifeniza o
     texto do estudo, e o campo herdava — um traço no meio de um identificador
     Python é código que não existe. Aqui se recusa a herança, e não se muda a
     prosa. */
  white-space: pre;
  hyphens: none;
  word-break: normal;
  overflow-wrap: normal;
  /* A altura vem do `rows`, que o módulo recalcula a cada tecla, e o teto é
     desta folha: sem ele, uma célula de cem linhas empurra a saída e o ▶ para
     fora da tela e o leitor rola a PÁGINA para achar o que está editando. No
     teto, quem rola é o campo. A alça de redimensionar daria ao leitor um
     segundo controle da mesma coisa, que desandaria no primeiro `input`. */
  max-height: 60vh;
  resize: none;
  overflow: auto;
  -webkit-tap-highlight-color: transparent;
}
.prosa .cerca.com-rodar > textarea.celula-editor { padding-right: calc(3.4rem + 44px + .4rem); }
/* A guarda da L-120: `[hidden]` só vem da folha do navegador, e qualquer
   regra de autor que ponha `display` num `pre` a venceria em silêncio — o
   leitor veria o código duas vezes, um em cima do outro na mesma célula da
   grade. Declarada aqui, a intenção não depende de ninguém não mexer ali. */
.prosa .cerca > pre[hidden] { display: none; }
.prosa .cerca > textarea.celula-editor:focus-visible { outline: 2px solid var(--foco); outline-offset: 1px; }

/* A marca e o desfazer, na terceira linha da grade — abaixo da saída, que é a
   segunda. A marca é conteúdo GERADO: rótulo é apresentação, e um `<span>` a
   mais dentro da cerca é um nó a mais no caminho do pintor de destaques. */
.prosa .cerca[data-modificada]::after {
  content: "modificada";
  grid-row: 3; grid-column: 1;
  justify-self: end; align-self: center;
  font-family: var(--mono); font-size: .72em; letter-spacing: .04em;
  color: var(--foco);
  padding-top: .25rem;
}
.prosa .cerca > button.restaurar {
  grid-row: 3; grid-column: 1;
  justify-self: start;
  margin-top: .25rem;
  padding: 0 .6rem;
  /* 44 de altura, como manda o núcleo: o botão é discreto pela TINTA e pelo
     corpo da letra, nunca pelo alvo — encolher o alvo é o defeito que a lente
     pegou em 07/09, e quem lê num iPad toca com o polegar. */
  min-height: var(--alvo);
  border: 1px solid var(--borda-controle); border-radius: 6px;
  background: none;
  color: var(--tinta-suave, var(--tinta));
  font-family: var(--corpo); font-size: .78em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) {
  .prosa .cerca > button.restaurar:hover { color: var(--foco); border-color: var(--foco); }
}
.prosa .cerca > button.restaurar:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* O pulso do mostrador da bancada: a única animação da cápsula, e ela diz uma
   coisa só — a célula ainda está rodando lá longe. */
@keyframes bancada-pulso { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }

/* O painel das fontes  (spec 42 §3.4): uma linha por dado, no pé do artigo.
   Compacto — nome, estado, para quê, host — e os botões da decisão
   com a mesma cara dos da barra, menores. O estado fala pela cor da situação:
   pronta no acento, pendente na tinta suave, falha e recusa no perigo. */
.bancada-fontes {
  margin: .5rem 0 0;
  padding: .35rem .9rem;
  border: 1px solid var(--borda-controle); border-radius: 12px;
  background: var(--papel-elev);
  font-size: .85em;
}
.bancada-fontes .fonte {
  display: flex; flex-wrap: wrap; gap: .25rem .7rem; align-items: center;
  padding: .3rem 0;
  font-variant-numeric: tabular-nums;
}
.bancada-fontes .fonte + .fonte { border-top: 1px solid var(--borda-controle); }
.bancada-fontes .fonte .nome { font-family: var(--mono); font-size: .95em; }
.bancada-fontes .fonte .situacao { color: var(--tinta-suave, var(--tinta)); }
.bancada-fontes .fonte[data-estado="pronto"] .situacao { color: var(--foco); }
.bancada-fontes .fonte[data-estado="falhou"] .situacao,
.bancada-fontes .fonte[data-estado="recusada"] .situacao,
.bancada-fontes .fonte .falha-decisao { color: var(--perigo); }
.bancada-fontes .fonte[data-estado="baixando"] .situacao::before {
  content: ""; display: inline-block; width: .5em; height: .5em; border-radius: 50%;
  background: var(--foco); margin-right: .45em; vertical-align: middle;
  animation: bancada-pulso 1.1s ease-in-out infinite;
}
.bancada-fontes .fonte .para-que { flex: 1 1 12rem; color: var(--tinta-suave, var(--tinta)); }
.bancada-fontes .fonte .host { font-family: var(--mono); font-size: .85em; opacity: .7; }
.bancada-fontes .fonte .decisao { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; margin-left: auto; }
.bancada-fontes .fonte .decisao button {
  min-height: var(--alvo); padding: 0 .7rem;
  border: 1px solid var(--borda-controle); border-radius: 8px;
  background: var(--papel); color: var(--tinta);
  font: inherit; font-size: .95em; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.bancada-fontes .fonte .decisao button[data-acao="aprovar"],
.bancada-fontes .fonte .decisao button[data-acao="repetir"] { color: var(--foco); border-color: var(--foco); }
.bancada-fontes .fonte .decisao button[data-acao="recusar"],
.bancada-fontes .fonte .decisao button[data-acao="recusar-confirmar"] { color: var(--perigo); border-color: currentColor; }
.bancada-fontes .fonte .decisao button:disabled { opacity: .5; cursor: default; }
.bancada-fontes .fonte .decisao button:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }
.bancada-fontes .fonte .decisao input {
  min-height: var(--alvo); padding: 0 .6rem;
  border: 1px solid var(--borda-controle); border-radius: 8px;
  background: var(--papel); color: var(--tinta);
  font: inherit; font-size: .95em;
  flex: 1 1 10rem;
}
.bancada-fontes .fontes-aviso { margin: .3rem 0 .15rem; color: var(--tinta-suave, var(--tinta)); font-style: italic; }


.prosa pre.diagrama > button.ampliar {
  position: absolute;
  top: .2rem; right: .2rem;
  /* 44 nos dois eixos, e não 34: o núcleo impõe `min-height: var(--alvo)` a
     todo `button`, e um `height` menor só produziria um retângulo. */
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 1px solid var(--borda-controle); border-radius: 8px;
  background: var(--papel-elev);
  color: var(--tinta);
  cursor: pointer;
  transition: color .15s ease, border-color .15s ease;
  -webkit-tap-highlight-color: transparent;
}
.prosa pre.diagrama > button.ampliar::before {
  content: "⤢";
  font: 16px/1 var(--fonte-interface, system-ui, sans-serif);
  user-select: none; -webkit-user-select: none;
}
@media (hover: hover) {
  .prosa pre.diagrama > button.ampliar:hover { color: var(--foco); border-color: var(--foco); }
}
.prosa pre.diagrama > button.ampliar:focus-visible {
  outline: 2px solid var(--foco); outline-offset: 2px;
}

/* ─────────────────────────────────────────────────────────────────────────────
   A lente — o desenho em tela cheia  (07/09)

   Fundo OPACO, e não um véu: o diagrama é linha fina sobre papel, e um texto
   de artigo aparecendo por trás dele compete com as arestas exatamente onde a
   leitura é mais difícil.

   `touch-action: none` porque os gestos são nossos: sem isto o Safari faz o
   seu próprio pinch-zoom da página e o desenho fica preso no meio dos dois.
   ───────────────────────────────────────────────────────────────────────── */

#lente {
  position: fixed; inset: 0; z-index: 85;
  display: none;
  background: var(--papel);
  touch-action: none;
  overscroll-behavior: contain;
  overflow: hidden;
  cursor: grab;
}
#lente[data-aberto="sim"] { display: block; }
#lente:active { cursor: grabbing; }

/* O palco é o que se move e escala. `transform-origin: 0 0` não é gosto: toda
   a aritmética de `lente.mjs` — o zoom ancorado no dedo e o limite do arrasto
   — assume o canto como origem, e o padrão (`50% 50%`) faria cada conta errar
   por meia largura, em silêncio. */
#lente .palco {
  position: absolute; top: 0; left: 0;
  transform-origin: 0 0;
  will-change: transform;
}
#lente .palco svg { display: block; }

#lente .fechar {
  position: absolute; z-index: 2;
  top: calc(.6rem + env(safe-area-inset-top));
  right: calc(.6rem + env(safe-area-inset-right));
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 1px solid var(--borda-controle); border-radius: 50%;
  background: var(--papel-elev);
  color: var(--tinta);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
#lente .fechar::before {
  content: "✕";
  font: 17px/1 var(--fonte-interface, system-ui, sans-serif);
  user-select: none; -webkit-user-select: none;
}
#lente .fechar:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* A dica de gesto. Pinça e duplo-toque não têm affordance nenhuma na tela —
   ou se diz que existem, ou elas não existem. Discreta e fixa: um aviso que
   some sozinho depois de três segundos é um aviso que só quem já sabia leu. */
#lente .dica {
  position: absolute; z-index: 2;
  left: 50%; transform: translateX(-50%);
  bottom: calc(.7rem + env(safe-area-inset-bottom));
  margin: 0;
  font: 12px/1.3 var(--fonte-interface, system-ui, sans-serif);
  letter-spacing: .02em;
  color: var(--tenue);
  opacity: .7;
  pointer-events: none;
  user-select: none; -webkit-user-select: none;
}

/* A `leitura` do recurso — o parágrafo em itálico logo abaixo do desenho. É o
   campo que impede o diagrama de ser enfeite, e por isso ele se lê como legenda
   e não como corpo. */
.prosa pre.diagrama + p em,
.prosa pre.diagrama + p > em:only-child {
  font-style: italic;
  color: var(--tinta-fraca);
}

/* Diagrama que não compilou fica como fonte à vista: feio, e honesto. O
   contrário — sumir em silêncio — é o defeito que a spec 23 chama de sucesso
   mudo, do lado do cliente. */
.prosa pre.diagrama-falhou { border-left: 2px solid var(--foco); }

/* ── O destaque de sintaxe ───────────────────────────────────────────────────
   Sete papéis, e não a paleta de 40 tokens do highlight.js: num estudo o
   código é lido devagar, e um arco-íris compete com a explicação ao redor.
   As cores saem dos tokens da folha, então os três temas seguem juntos. */

.prosa pre code.hljs { color: var(--tinta); }
.prosa .hljs-comment, .prosa .hljs-quote { color: var(--tinta-fraca); font-style: italic; }
.prosa .hljs-keyword, .prosa .hljs-selector-tag, .prosa .hljs-literal,
.prosa .hljs-doctag, .prosa .hljs-meta .hljs-keyword { color: var(--acento); font-weight: 600; }
.prosa .hljs-string, .prosa .hljs-regexp, .prosa .hljs-addition { color: var(--realce-texto); }
.prosa .hljs-number, .prosa .hljs-symbol, .prosa .hljs-bullet { color: var(--realce-numero); }
.prosa .hljs-title, .prosa .hljs-title.function_, .prosa .hljs-section,
.prosa .hljs-name { color: var(--realce-nome); font-weight: 600; }
.prosa .hljs-attr, .prosa .hljs-attribute, .prosa .hljs-variable,
.prosa .hljs-params, .prosa .hljs-property { color: var(--tinta); }
.prosa .hljs-type, .prosa .hljs-built_in, .prosa .hljs-class .hljs-title {
  color: var(--realce-nome); }
.prosa .hljs-deletion { color: var(--perigo, #b3261e); }
.prosa .hljs-emphasis { font-style: italic; }
.prosa .hljs-strong { font-weight: 700; }

/* As três cores próprias do destaque, por tema. Medidas sobre `--papel-elev`,
   que é o fundo da cerca — não sobre `--papel`. */
[data-tema="claro"] { --realce-texto:#0f6b4f; --realce-numero:#7a4e00; --realce-nome:#1c4f8a; }
[data-tema="sepia"] { --realce-texto:#0e6249; --realce-numero:#74490a; --realce-nome:#1b4a80; }
[data-tema="escuro"] { --realce-texto:#7fd3ae; --realce-numero:#e0b062; --realce-nome:#8fbdf0; }

/* ══ A CAIXA DO LABORATÓRIO  (spec 43 §7.3) ═════════════════════════════════

   Da família do `#nota`/`#conversa`/`#colar` — mesmo papel, mesma borda, mesma
   sombra de objeto que paira —, com UMA diferença de fundo: ela atraca no
   chão. Os outros fugiram do rodapé em 21/08 porque o teclado do iPad os
   engolia; esta não pode fugir, porque o que interessa num terminal é a última
   linha, e a última linha vive no pé.

   O que resolve o teclado aqui não é mudar de lugar, é SUBIR: o
   `teclado-virtual.mjs` mede o vão (`innerHeight` menos o viewport visual) e
   escreve `--teclado`; o `bottom` daqui é o máximo entre esse vão e a área
   segura, porque com o teclado aberto não há barra de gestos a evitar e com
   ele fechado não há vão.

   E ela é LARGA: 48rem, contra as 36rem das irmãs. Um terminal se mede em
   colunas, e 36rem dão umas sessenta — abaixo do que qualquer `pip install`
   ou `traceback` supõe ao quebrar as próprias linhas. */
/* ── A moldura é de TODA caixa  (spec 56 §2) ───────────────────────────────
   A caixa do lab virou a caixa padrão de escrever: a da leitura (nota e
   pergunta) veste a mesma moldura. As regras da moldura se escrevem sobre os
   DOIS ids por `:is()`, e não sobre uma classe `.caixa`, por causa do peso: um
   `:is()` pesa o seu argumento mais pesado, e é o id que vence
   `.alca { display: none }` (a alça de seleção da Pencil) e, sobretudo,
   `body[data-dentro] .cabeca { display: none }` — a regra do modo lateral
   que esconde o cabeçalho da PÁGINA. Com uma classe (0,2,0) contra (0,2,1), a
   cabeça da caixa da leitura sumiria no Mac, justamente com o `⌄` dentro.
   O que é de uma caixa só — largura, altura de partida, o terminal — fica no
   id dela. */
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) {
  top: auto;
  bottom: max(var(--teclado, 0px), env(safe-area-inset-bottom));
  /* O teto com o teclado aberto é do JS (`limitesDaCaixa` ouve a área
     visível). Um `min(70vh, calc(100svh - var(--teclado)…))` aqui foi
     DESCARTADO pelo WebKit do simulador em 17/09 (medido: valia o
     `min(70vh, 34rem)` do `.sheet`), e isso prenderia a caixa do lab em 34rem
     no iPad. */
  max-height: 70vh;
  min-height: 160px;
  padding: 0;
  gap: 0;
  overflow: hidden;
}
/* A altura é o token que a alça escreve. Sem preferência guardada o módulo
   não escreve NADA e vale o padrão daqui — 40vh, que é caixa e não tela. */
#caixa-lab {
  width: min(48rem, calc(100% - 1.5rem));
  height: var(--caixa-lab-h, 40vh);
}
/* A entrada vem de BAIXO, e não de cima: o objeto nasce da borda em que ele
   está ancorado. A regra da família anima `sheet-entra`, que desce 8px — na
   caixa isso seria a mesma animação de um painel do topo, tocada no chão. */
:is(#caixa-lab, #caixa-leitura, #caixa-destaques)[data-aberto="sim"] { animation: caixa-lab-entra .16s var(--curva); }
@keyframes caixa-lab-entra { from { transform: translate(-50%, 8px); } }

/* ── A alça ────────────────────────────────────────────────────────────────
   `.alca` já existe nesta folha, para as alças de seleção da Pencil, e lá ela
   nasce `display: none`. As regras daqui têm o id na frente e por isso vencem
   — mas o `display` precisa ser declarado, e não herdado, senão a alça da
   caixa some sem erro nenhum no console.

   44px de alvo (o mínimo de toque da casa) com um filete de 4px desenhado no
   meio: o dedo pega a faixa inteira, o olho vê a marca. */
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .alca {
  display: flex; align-items: center; justify-content: center;
  position: relative; z-index: auto;
  width: 100%; margin: 0; height: 22px; flex: none;
  cursor: ns-resize;
  /* Sem isto a página rola por baixo enquanto o dedo puxa — o gesto vira
     scroll no meio do caminho e a caixa fica presa onde estava. */
  touch-action: none;
  -webkit-user-select: none; user-select: none;
}
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .alca > i {
  display: block; position: static;
  width: 44px; height: 4px; margin: 0;
  border-radius: 2px; background: var(--regra);
}
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .alca:hover > i, :is(#caixa-lab, #caixa-leitura, #caixa-destaques) .alca.puxando > i { background: var(--acento); }
/* O botão redondo de 18px é o puxador da alça de SELEÇÃO da Pencil
   (`.alca > i::after`), e casava aqui pelo nome: a captura do simulador em
   17/09 mostrou um círculo marrom pendurado no filete da caixa. */
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .alca > i::after { content: none; }

/* ── A cabeça: as abas à esquerda, os quatro botões à direita ──────────────
   Ela encolhe até virar duas fileiras nas telas estreitas: no iPhone as quatro
   ações não cabem ao lado das abas, e apertá-las abaixo do alvo de toque seria
   trocar um controle por um enfeite. */
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .cabeca {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: .4rem;
  flex: none;
  /* `max-width` e `margin` DECLARADOS, e não herdados. `.cabeca` é a classe do
     cabeçalho da PÁGINA (`.cabeca { max-width: var(--measure); margin: 0 auto }`,
     lá em cima), e a caixa reusou o nome: sem estas duas linhas a cabeça da
     caixa nasce com 34,5em e centrada dentro de 48rem — o `space-between`
     aproxima as abas dos botões, e o filete de baixo, que devia riscar a caixa
     inteira, vira um traço curto no meio. Medido no Safari em 09/09, pelo
     `npm run bancada`: 464px de cabeça numa caixa de 768px. */
  max-width: none; margin: 0;
  padding: 0 .8rem .5rem;
  border-bottom: 1px solid var(--regra);
}
/* `:not([hidden])`: com uma aba só (Destaques) a fileira nasce `hidden`, e um
   `display` de autor venceria o atributo — a armadilha da guarda do painel. */
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .abas:not([hidden]) { display: flex; gap: .1rem; }
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .abas [role="tab"] {
  font-family: var(--sans); font-size: .82rem; font-weight: 600;
  color: var(--tenue); background: none; border: none;
  border-bottom: 2px solid transparent;
  padding: .35rem .7rem; min-height: 32px; cursor: pointer;
}
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .abas [role="tab"][aria-selected="true"] {
  color: var(--tinta); border-bottom-color: var(--acento);
}
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .abas [role="tab"]:focus-visible { outline: 2px solid var(--foco); outline-offset: -2px; }
#caixa-lab .botoes { display: flex; gap: .35rem; flex-wrap: wrap; }
/* ── Recolher, e a cabeça no telefone  (14/09) ──────────────────────────────
   O «recolher» fecha a CAIXA (o «Fechar» ao lado encerra o lab). Um glifo, no
   tamanho de alvo, sem campo: é a porta de saída, não uma ação do lab. No
   telefone a cabeça já quebra em duas linhas (abas em cima, botões embaixo);
   o recolher vai para a ponta direita da linha das abas, onde o polegar o
   acha sem ler — e os quatro botões descem inteiros para a segunda linha. */
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .recolher {
  margin-left: auto; width: 32px; height: 32px; flex: none;
  border: 0; background: none; color: var(--tenue); cursor: pointer;
  font-family: var(--sans); font-size: 1.15rem; line-height: 1;
  border-radius: var(--raio-p);
  display: grid; place-items: center;
}
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .recolher:hover, :is(#caixa-lab, #caixa-leitura, #caixa-destaques) .recolher:focus-visible { color: var(--tinta); }
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .recolher:focus-visible { outline: 2px solid var(--foco); outline-offset: -2px; }
@media (max-width: 40rem) {
  :is(#caixa-lab, #caixa-leitura, #caixa-destaques) .abas { order: 1; }
  :is(#caixa-lab, #caixa-leitura, #caixa-destaques) .recolher { order: 2; }
  #caixa-lab .botoes { order: 3; width: 100%; }
}
/* Na barra do rodapé do telefone a caixa pousa ACIMA da barra, e não sobre
   ela: o `>_` que a abriu continua na tela, e a barra continua sendo a barra.
   Com o teclado aberto vale o vão dele, que é maior. */
body[data-arranjo="barra"] :is(#caixa-lab, #caixa-leitura, #caixa-destaques) {
  bottom: max(var(--teclado, 0px), var(--pilha-y));
  max-height: 60vh;
}
/* «Reiniciar o kernel» é o gesto raro e caro desta caixa, e o único que pede
   confirmação. Ele não veste o acento — chamar a mão para o que se arrepende
   depois é o contrário do que o preço declarado existe para fazer. */
#caixa-lab .botoes .btn { font-size: .74rem; padding: .3rem .55rem; }

/* ── Os painéis ───────────────────────────────────────────────────────────
   Quem rola é o painel, e não a caixa: a cabeça com as abas e os quatro botões
   fica presa no alto, sempre alcançável, como a linha de botões do `#conversa`
   fica presa no pé. Controle que sai da tela é controle que não existe. */
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .painel {
  flex: 1 1 auto; min-height: 0; overflow: auto;
  padding: .6rem .8rem .8rem;
}
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .painel:focus-visible { outline: 2px solid var(--foco); outline-offset: -2px; }
/* A aba Shell é COLUNA: a tarja do «sem kernel» fica presa no alto e o corpo
   rola por baixo dela. Um aviso que rolasse junto com a saída sairia da tela
   no terceiro comando, e é no terceiro comando que ele mais importa. */
#caixa-lab .painel.shell:not([hidden]) { display: flex; flex-direction: column; overflow: hidden; }
#caixa-lab .shell-corpo { flex: 1 1 auto; min-height: 0; overflow: auto; }
/* A guarda do `[hidden]`: o `display` de autor acima venceria o
   `[hidden] { display: none }` do navegador, e o painel escondido pela troca
   de aba ficaria na tela por baixo do outro.

   A guarda era só ORDEM — «mesma especificidade, e depois dela». Ordem só
   segura enquanto ninguém escrever mais específico, e a aba Conversa (§8)
   escreveu: `#caixa-lab #caixa-lab-conversa[role="tabpanel"]` tem dois ids e
   passa por cima daqui. O resultado, medido no Safari em 09/09 pelo
   `npm run bancada`: com a Shell aberta, o painel da Conversa continuava na
   tela — campo, botão «Perguntar» e 180px roubados da caixa, que sobravam 84
   para o terminal. Um `fit()` sobre 84px dá seis linhas, e seis linhas de
   terminal numa caixa de 379 é o defeito que nenhum teste de estado vê.

   Por isso o `:not([hidden])` nas regras de FORMA, e não mais um degrau de
   especificidade aqui: quem esconde é o atributo, e nenhuma regra de aparência
   se aplica a um painel escondido — independentemente de ordem e de peso. */
:is(#caixa-lab, #caixa-leitura, #caixa-destaques) .painel[hidden] { display: none; }
/* A tarja: perigo, porque o que ela anuncia é uma tecla que some. */
#caixa-lab .sem-kernel {
  flex: none; margin: 0 0 .5rem;
  font-family: var(--sans); font-size: .78rem; color: var(--perigo);
}
/* Sem linha o terminal se apaga um pouco: ele continua legível (o histórico é
   o trabalho), e deixa de parecer que está esperando o que se digita. */
#caixa-lab[data-sem-kernel] .terminal { opacity: .6; }

/* O terminal precisa de CAIXA: o FitAddon divide a altura disponível pela
   altura do glifo, e uma caixa de zero dá zero linha — o `fit()` roda, não
   falha, e o terminal fica com uma linha só. O `min-height` é o piso de duas
   dúzias de linhas a 13px; o `height: 100%` é o que faz ele crescer com a
   alça. */
#caixa-lab .terminal {
  width: 100%; height: 100%; min-height: 96px;
  /* Preto porque é o fundo que o xterm pinta por dentro (o padrão do tema
     dele). Os dois são um fato só: um container de outra cor apareceria como
     uma moldura que não é de ninguém quando o terminal tem menos linhas que a
     caixa. */
  background: #000;
  border-radius: var(--raio-p);
  overflow: hidden;
}

/* ── A reserva: a linha de comando sem pty ─────────────────────────────────
   Ela é declarada, e a frase é o que a declara. Sem ela o leitor acha que
   ISTO é o Shell e vai culpar o app quando o `vim` não abrir. */
#caixa-lab .sem-xterm {
  font-family: var(--sans); font-size: .78rem; color: var(--perigo);
  margin: 0 0 .5rem;
}
#caixa-lab .saida-pty {
  font-family: var(--mono); font-size: .82rem; line-height: 1.45;
  color: var(--tinta); background: var(--papel-elev-2);
  border: 1px solid var(--regra); border-radius: var(--raio-p);
  padding: .5rem .6rem; margin: 0 0 .5rem;
  max-height: 60vh; overflow: auto; white-space: pre-wrap; word-break: break-word;
}
#caixa-lab .linha-comando { display: flex; align-items: center; gap: .4rem; }
#caixa-lab .linha-comando .rotulo {
  font-family: var(--mono); font-size: .9rem; color: var(--tenue); flex: none;
}
/* 1rem, e não menos: abaixo de 16px o iOS DÁ ZOOM ao focar o campo, e a página
   salta com a caixa junto. É o mesmo número dos dois `textarea` da folha. */
#caixa-lab .linha-comando input {
  flex: 1; min-width: 0; box-sizing: border-box;
  font-family: var(--mono); font-size: 1rem; color: var(--tinta);
  background: var(--papel); border: 1px solid var(--borda-controle);
  border-radius: var(--raio-p); padding: .45rem .6rem; min-height: var(--alvo);
  -webkit-appearance: none; appearance: none;
}
#caixa-lab .linha-comando input:focus-visible { outline: none; border-color: var(--acento); }

/* ── A aba Conversa: a assistente do lab  (spec 43 §8) ─────────────────────
   Mesma gramática do `#conversa` do artigo — lista que rola, campo, linha de
   botão presa no pé —, porque é a mesma conversa em outro lugar: o leitor não
   deve ter de aprender duas vezes onde se digita.
   O painel vira coluna aqui (e não no `.painel` genérico) porque o Shell quer
   o contrário: lá o terminal ocupa a caixa inteira.

   O `:not([hidden])` é o que faz esta regra — dois ids — não atropelar a
   guarda do `[hidden]` lá em cima. Ver o comentário dela. */
#caixa-lab #caixa-lab-conversa[role="tabpanel"]:not([hidden]) {
  display: flex; flex-direction: column; gap: 0;
}
#caixa-lab .turnos { flex: 1 1 auto; min-height: 3rem; overflow-y: auto; margin-bottom: .7rem; }
#caixa-lab .turnos .vazio {
  color: var(--tinta-2); font-size: .88rem; text-align: center; margin: 1.2rem 0;
}
#caixa-lab .turno { margin-bottom: .9rem; }
#caixa-lab .turno .p {
  font-family: var(--sans); font-weight: 600; color: var(--tinta); font-size: .9rem;
  margin: 0 0 .3rem; white-space: pre-wrap;
}
#caixa-lab .turno .r {
  font-family: var(--sans); color: var(--tinta-2); font-size: .9rem; line-height: 1.55;
  margin: 0; white-space: pre-wrap;
}
#caixa-lab .turno .r code {
  font-family: var(--mono); font-size: .84em; background: var(--papel-elev-2);
  border-radius: var(--raio-p); padding: .05rem .25rem;
}

/* A proposta é um bloco à parte, recuado: ela não é a resposta, é o que a
   resposta oferece — e o recuo é o que diz isso sem uma legenda. */
#caixa-lab .proposta {
  margin: .5rem 0 0; padding: .5rem .6rem;
  border-left: 3px solid var(--regra); background: var(--papel-elev-2);
  border-radius: var(--raio-p);
}
/* A cerca ROLA, e não estica: código de uma linha longa alargaria a caixa
   inteira, e a caixa está atracada na largura da janela. */
#caixa-lab .proposta pre {
  margin: 0 0 .4rem; padding: 0; overflow-x: auto;
  font-family: var(--mono); font-size: .8rem; line-height: 1.45;
  color: var(--tinta); white-space: pre;
}
#caixa-lab .proposta .estado {
  font-family: var(--sans); font-size: .78rem; color: var(--tinta-2);
  margin: 0 0 .4rem; white-space: pre-wrap; word-break: break-word;
}
#caixa-lab .proposta .aplicar { font-size: .76rem; padding: .3rem .55rem; }
/* Desabilitado é ESTADO, e tem de parecer estado: a proposta que ainda não
   rodou (ou que falhou) não pode ter a mesma cara da que rodou. */
#caixa-lab .proposta .aplicar[disabled] { opacity: .5; cursor: default; }

/* A resposta tem parágrafos e cercas (13/09): o `<p>` herdaria a margem do
   núcleo, e o `code` de dentro da cerca herdaria a pílula do `code` inline. */
#caixa-lab .turno .r p { margin: 0 0 .45rem; }
#caixa-lab .turno .r p:last-child { margin-bottom: 0; }
#caixa-lab .turno .r .cerca { margin: .2rem 0 .5rem; }
#caixa-lab .turno .r .cerca > pre {
  padding: .45rem .6rem; background: var(--papel-elev-2); border-radius: var(--raio-p);
  font-family: var(--mono); font-size: .8rem; line-height: 1.45;
  color: var(--tinta); white-space: pre;
}
#caixa-lab .turno .cerca pre code { background: none; padding: 0; border-radius: 0; font-size: inherit; }

/* O botão de copiar é o MESMO da prosa (`cercar`, em desenho.mjs), e as regras
   de lá são `.prosa .cerca`: a caixa não mora na prosa. A grade põe o botão por
   cima do canto da cerca, e a cerca rola por baixo dele. */
#caixa-lab .cerca { display: grid; }
#caixa-lab .cerca > pre, #caixa-lab .cerca > button.copiar { grid-area: 1 / 1; }
#caixa-lab .cerca > pre { padding-right: 3.2rem; overflow-x: auto; margin: 0; }
#caixa-lab .cerca > button.copiar {
  justify-self: end; align-self: start; margin: .15rem;
  width: 44px; height: 44px; display: grid; place-items: center;
  border: 1px solid var(--borda-controle); border-radius: 8px;
  background: var(--papel-elev); color: var(--tinta); cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
#caixa-lab .cerca > button.copiar svg { width: 16px; height: 16px; grid-area: 1 / 1; }
#caixa-lab .cerca > button.copiar .ic-copiado { display: none; }
#caixa-lab .cerca > button.copiar[data-estado="copiado"] { color: var(--foco); border-color: var(--foco); }
#caixa-lab .cerca > button.copiar[data-estado="copiado"] .ic-copiar { display: none; }
#caixa-lab .cerca > button.copiar[data-estado="copiado"] .ic-copiado { display: block; }
#caixa-lab .cerca > button.copiar[data-estado="falhou"] { color: var(--perigo); border-color: currentColor; }
#caixa-lab .cerca > button.copiar:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* 1rem pelo mesmo motivo da linha de comando acima: abaixo de 16px o iOS dá
   zoom ao focar o campo, e a página salta com a caixa junto. */
#caixa-lab #caixa-lab-txt {
  flex: none; display: block; width: 100%; min-height: 3.2rem; resize: vertical;
  font-family: var(--sans); font-size: 1rem; line-height: 1.5; color: var(--tinta);
  background: var(--papel); border: 1px solid var(--borda-controle); border-radius: 8px;
  padding: .6rem .7rem; box-sizing: border-box;
}
#caixa-lab #caixa-lab-txt:focus-visible { outline: none; border-color: var(--acento); }
#caixa-lab #caixa-lab-conversa .linha {
  flex: none; display: flex; align-items: center; gap: .5rem; margin-top: .7rem;
}
#caixa-lab #caixa-lab-conversa .linha .sub { flex: 1; font-size: .78rem; color: var(--tinta-2); }
#caixa-lab #caixa-lab-perguntar[disabled] { opacity: .55; }

/* ══ A CAIXA DA LEITURA  (spec 56) ═════════════════════════════════════════

   A nota e a pergunta, que eram folhas no TOPO — sobre o parágrafo em que se
   pensava —, viram duas abas desta caixa, que atraca embaixo com a moldura do
   lab (acima). Lê-se em cima, escreve-se embaixo. A tela de Destaques usa a
   mesma caixa só com a aba Nota (`#caixa-destaques`).

   Mais estreita que a do lab: 40rem. A do lab se mede em colunas de terminal;
   esta se mede na linha de prosa que se escreve, e uma nota de 48rem no Mac
   teria linhas mais longas que as do próprio texto ao lado. */
#caixa-leitura {
  width: min(40rem, calc(100% - 1.5rem));
  /* 42vh: no iPhone deitado de teclado aberto a moldura grampeia no piso, e
     no iPad sobra texto acima para ler o parágrafo inteiro. */
  height: var(--caixa-leitura-h, 42vh);
}
#caixa-destaques {
  width: min(40rem, calc(100% - 1.5rem));
  height: var(--caixa-destaques-h, 36vh);
}

/* ── A cabeça do foco: SOBRE O QUE se escreve ────────────────────────────────
   Uma linha, cortada com reticências; o toque abre inteira. Escrever a nota
   sobre o trecho errado é o erro que ninguém percebe na hora, e é por isso
   que o trecho fica à vista em cima do campo — e pisca uma vez quando troca
   com a caixa aberta (spec 56 §4). */
:is(#caixa-leitura, #caixa-destaques) .foco {
  flex: none; display: block; box-sizing: border-box;
  width: calc(100% - 1.6rem); margin: .55rem .8rem 0; padding: .15rem .6rem;
  min-height: 32px;
  text-align: left; font-family: var(--corpo); font-size: .9rem; line-height: 1.45;
  color: var(--tinta-2); background: none;
  border: 0; border-left: 2px solid var(--acento); border-radius: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  cursor: pointer;
}
:is(#caixa-leitura, #caixa-destaques) .foco[data-inteiro="sim"] { white-space: normal; max-height: 30vh; overflow-y: auto; }
:is(#caixa-leitura, #caixa-destaques) .foco:disabled { cursor: default; font-family: var(--sans); font-size: .82rem; opacity: 1; }
:is(#caixa-leitura, #caixa-destaques) .foco:focus-visible { outline: 2px solid var(--foco); outline-offset: -2px; }
:is(#caixa-leitura, #caixa-destaques) .foco[data-trocou="sim"] { animation: caixa-foco-trocou .7s var(--curva); }
@keyframes caixa-foco-trocou {
  from { background: color-mix(in srgb, var(--acento) 28%, transparent); }
}

/* ── As abas são COLUNA: o campo e a linha de status presos no pé ────────────
   A mesma razão do `#conversa` (L-81): quem rola é a lista de turnos, nunca o
   campo — controle que sai da tela é controle que não existe. O
   `:not([hidden])` é o invariante da moldura: regra de forma não alcança
   painel escondido. */
:is(#caixa-leitura, #caixa-destaques) .painel:not([hidden]) { display: flex; flex-direction: column; gap: 0; }
/* Os filhos das abas herdam da folha antiga `max-width: var(--measure);
   margin-inline: auto`, que numa coluna flex ENCOLHE o filho ao conteúdo: o
   botão «Perguntar» saía centrado e a lista de turnos estreita (simulador,
   17/09). Na caixa a medida é a da própria caixa. */
:is(#caixa-leitura, #caixa-destaques) .painel > * { max-width: none; margin-inline: 0; align-self: stretch; }
/* O trecho de dentro das abas é o da folha antiga; na caixa quem o mostra é a
   cabeça, e dois trechos iguais um sobre o outro seriam ruído. */
:is(#caixa-leitura, #caixa-destaques) .painel .trecho { display: none; }
/* A nota ocupa a caixa: o campo cresce com a alça, e a linha fica no pé. */
:is(#caixa-leitura, #caixa-destaques) #nota-txt { flex: 1 1 auto; min-height: 3.2rem; resize: none; box-sizing: border-box; }
:is(#caixa-leitura, #caixa-destaques) .painel .linha { flex: none; justify-content: flex-end; }
/* `campo.hidden` e `linha.hidden` quando o foco não é destaque: o `display`
   das regras da nota (`#nota textarea`, `#nota .linha`) venceria o atributo. */
#caixa-leitura-nota textarea[hidden], #caixa-destaques-nota textarea[hidden],
#caixa-leitura-nota .linha[hidden], #caixa-destaques-nota .linha[hidden] { display: none; }
:is(#caixa-leitura, #caixa-destaques) .sem-destaque {
  font-family: var(--sans); font-size: .88rem; color: var(--tinta-2);
  text-align: center; margin: 1.2rem 0;
}
:is(#caixa-leitura, #caixa-destaques) .sem-destaque[hidden] { display: none; }

/* ── O capítulo  (spec 50 §3.1–3.2, F2) ──────────────────────────────────────
   A moldura mínima. A tipografia literária (capitular, recuo, versalete da
   parte) é da F3 e entra por cima destes seletores.

   Cabeçalho e rodapé vivos seguem UM sinal, o `data-cromo` do corpo que
   `criarCromo` escreve: rolando para baixo o cabeçalho sai e o rodapé entra
   (a barra de navegação também sai, e o pé da tela fica livre); rolando para
   cima, o contrário. Dois sinais para «rolou para baixo» divergiriam. */
.cabecalho-vivo {
  position: fixed; top: 0; left: 0; right: 0; z-index: 30;
  /* O mesmo inset do topo que a `.cabeca` (16/09): fixo em `top: 0`, sem ele
     o título corrente morava atrás do relógio do iPhone. */
  padding: calc(.5rem + env(safe-area-inset-top, 0px)) 1rem .5rem;
  font: 500 .8125rem/1.3 var(--sans); color: var(--tenue);
  background: var(--papel); border-bottom: 1px solid var(--regra);
  text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: transform var(--dur) var(--curva);
}
body[data-cromo="oculto"] .cabecalho-vivo { transform: translateY(-100%); }

.rodape-vivo {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 30;
  padding: .4rem 1rem calc(.4rem + env(safe-area-inset-bottom));
  font: 500 .75rem/1.3 var(--sans); color: var(--tenue);
  background: var(--papel); text-align: center; pointer-events: none;
  transition: opacity var(--dur) var(--curva);
}
body:not([data-cromo="oculto"]) .rodape-vivo { opacity: 0; }

.respiracao {
  margin: 4rem auto 5rem; max-width: 34rem; text-align: center;
  font-family: var(--serif-leitura); color: var(--tinta);
}
.respiracao-vinheta { font-size: 2rem; color: var(--tenue); margin: 0 0 2rem; }

/* ── A sala do fim  (spec 64) ────────────────────────────────────────────────
   A pergunta sobre o texto inteiro morava no TOPO da margem: quem lia o
   capítulo e perguntava no fim rolava o livro inteiro para trás para ler a
   resposta — e lá em cima ela nascia atrás do cabeçalho vivo, que é `fixed` e
   opaco (61 px medidos).

   Aqui ela fica onde o gesto acontece. A seção é irmã da respiração e a
   moldura segue a dela: a mesma coluna de leitura, centrada, e um rótulo em
   versalete entre dois filetes — o mesmo vocabulário do ❦, que é o que separa
   o fim do texto do que vem depois dele. */
.sala {
  max-width: var(--measure); margin: 2.5rem auto 1rem;
  font-family: var(--sans);
}
.sala-titulo {
  display: flex; align-items: center; gap: .75rem;
  margin: 0 0 1.1rem; font: 500 .8rem/1.3 var(--sans); color: var(--tenue);
  font-variant-caps: all-small-caps; letter-spacing: .08em; text-align: center;
}
.sala-titulo::before, .sala-titulo::after {
  content: ""; flex: 1; height: 1px; background: var(--regra);
}
/* Na página a conversa NÃO rola dentro de si: ela cresce com o texto, como
   qualquer coisa que se lê rolando. A rolagem interna é do sheet, onde o campo
   precisa ficar alcançável com o polegar por mais longa que a conversa fique. */
.sala .turnos { flex: none; overflow: visible; max-height: none; }
.sala .turnos .vazio { font-style: italic; }
.sala-antes {
  margin: -.4rem 0 1rem; font-size: .8rem; color: var(--tinta-2); font-style: italic;
}

/* ── A conversa falada no fio  (spec 64 §6) ──────────────────────────────────
   Escolha do dono entre as duas formas, olhando as duas: a transcrição aberta
   no fio, e não um título que abre um painel. O bloco é o MESMO turno dos
   escritos — mesma pergunta em cima, mesma resposta com filete —, com uma
   cabeça que diz de onde ele veio e um fio à esquerda que o mantém junto: uma
   conversa de seis minutos são muitos parágrafos, e sem ele o fim dela não
   pareceria pertencer ao começo. */
.sala .turno.falado {
  border-left: 2px solid var(--regra); padding-left: .8rem;
}
.sala .turno.falado .falado-cabeca {
  display: flex; align-items: center; gap: .4rem; margin: 0 0 .5rem;
  font: 500 .78rem/1.3 var(--sans); color: var(--tenue);
  font-variant-caps: all-small-caps; letter-spacing: .06em;
}
.sala .turno.falado .falado-cabeca .ic { display: inline-flex; width: 15px; height: 15px; }
.sala .turno.falado .falado-cabeca .ic svg { width: 15px; height: 15px; }
/* Os turnos de dentro da fala respiram menos que os de fora: são a mesma
   conversa, e o vão de um turno inteiro os faria parecer vários.

   `.falado-cabeca + .p`, e não `.p:first-of-type`: a cabeça TAMBÉM é um `<p>`,
   então `:first-of-type` nunca casaria com a primeira fala — seria uma regra
   escrita, publicada e morta. */
.sala .turno.falado .p { margin-top: .6rem; }
.sala .turno.falado .falado-cabeca + .p { margin-top: 0; }
.sala .turno.falado .falado-busca {
  margin: .4rem 0 0; font: italic .8rem/1.5 var(--sans); color: var(--tenue);
}
.sala-antes[hidden] { display: none; }
/* «ou falar com o autor»: o colóquio, que até a spec 64 era um botão do mesmo
   tamanho do «Próximo capítulo», ao lado dele. Aqui ele é a segunda via da
   MESMA conversa, e o desenho diz isso — uma linha discreta embaixo do campo,
   não um segundo convite competindo com o primeiro. */
.sala-ou {
  /* Flex, e não `text-align`: o botão tem 44px de alvo e a palavra «ou» tem a
     altura da linha — alinhados pela caixa, o «ou» pousava no pé do botão. */
  margin: .8rem 0 0; display: flex; align-items: center; justify-content: center;
  gap: .15rem; font-size: .82rem; color: var(--tinta-2);
}
.sala-coloquio {
  display: inline-flex; align-items: center; gap: .4rem;
  min-height: var(--alvo); padding: 0 .7rem; font-size: .82rem;
  background: none; border: 0; color: var(--tinta-2); cursor: pointer;
  text-decoration: underline; text-underline-offset: .2em;
}
.sala-coloquio:hover, .sala-coloquio:focus-visible { color: var(--tinta); }
.sala-coloquio .ic { display: inline-flex; width: 18px; height: 18px; }
.sala-coloquio .ic svg { width: 18px; height: 18px; }

/* O rodapé do capítulo é vazio de propósito (spec 64 §2.5): as ações de
   acervo são da OBRA e moram no frontispício e na Estante. Ele existe só
   porque `montarRodape` é um lugar só para as duas rotas. */
.rodape-capitulo { display: none; }
.respiracao-grifos { list-style: none; padding: 0; margin: 0 0 2rem; text-align: left; }
.respiracao-grifos li {
  border-left: 3px solid var(--regra); padding: .25rem 0 .25rem .75rem; margin: 0 0 .75rem;
}
.respiracao-proximo { font: 500 .9375rem/1.4 var(--sans); color: var(--tinta); }
.respiracao-acoes {
  display: flex; flex-wrap: wrap; gap: .75rem; justify-content: center; margin-top: 1rem;
}

/* A voz na respiração (spec 50 §5.6, F7): o aviso de que ela segue, e a
   pausa que oferece os dois caminhos. Só layout — a cor é a da respiração. */
.respiracao-voz { margin-block-start: 1.5em; text-align: center; }
.respiracao-voz .respiracao-acoes { justify-content: center; flex-wrap: wrap; }

/* ── O temperamento literário  (spec 50 §3.3, F3) ────────────────────────────
   Declarado pelo pipeline e escrito pelo leitor no <article>; o técnico é a
   AUSÊNCIA do atributo, e por isso é a tipografia de hoje sem uma linha a mais.

   Nada aqui toca o DOM do texto: a capitular é `::first-letter`, o numeral é
   `attr()`, o verso é `white-space`. Bids e offsets ficam como a ingestão os
   gravou — e a Pencil pergunta ao documento, não ao pixel.

   A capitular é UMA linha, de propósito: se a sondagem da alça reprovar
   (`web/test/sondagem-capitular.json`), ela sai apagando a linha, e o teste
   de CSS lê o veredito. Sem justificação: abre rios de branco (spec 02). */
.artigo[data-capitulo] .prosa > h1 { font-variant-caps: all-small-caps; letter-spacing: .08em; font-weight: 500; font-size: 1em; text-align: center; margin: 3rem 0 .25rem; color: var(--tinta); }
.artigo[data-capitulo] .prosa > [data-numeral] { text-align: center; margin-top: 1.25rem; }
.artigo[data-capitulo] .prosa > [data-numeral]::before { content: attr(data-numeral); display: block; font-size: .8em; font-weight: 400; letter-spacing: .12em; color: var(--tenue); margin-bottom: .35em; }
.artigo[data-temperamento="literario"] .prosa > p { margin: 0; text-indent: 1.5em; }
.artigo[data-temperamento="literario"] .prosa > p + :not(p) { margin-top: var(--space-para); }
.artigo[data-temperamento="literario"] .prosa > :is(h1, h2, h3, h4, h5, h6, hr, blockquote, figure, pre, ul, ol, table, section) + p,
.artigo[data-temperamento="literario"] .prosa > p.verso + p,
.artigo[data-temperamento="literario"] .prosa > p:first-child { text-indent: 0; }
.prosa > p.verso { white-space: pre-line; text-indent: 0; width: fit-content; max-width: 100%; margin-inline: auto; text-align: left; }
@supports (text-indent: 1em hanging each-line) {
  .prosa > p.verso { text-indent: 1.5em hanging each-line; }
}
.artigo[data-temperamento="literario"] .prosa > p.verso { margin-block: var(--space-para); }
.artigo[data-temperamento="literario"] .prosa > hr:not(.footnotes-sep) { border: 0; height: auto; margin: var(--space-block) 0; text-align: center; }
.artigo[data-temperamento="literario"] .prosa > hr:not(.footnotes-sep)::after { content: "❦"; color: var(--tenue); font-size: 1.1em; }

/* ── relembrar (spec 50 §5.5) ─────────────────────────────────────────────── */
.relembrar {
  margin: 0 0 1.25rem;
  padding: .6rem .8rem;
  border-left: 3px solid var(--acento);
  border-radius: var(--raio);
  background: var(--papel);
  color: var(--tinta);
  font-family: var(--sans);
  font-size: .9rem;
  line-height: 1.45;
}
.relembrar-rotulo { font-variant-caps: all-small-caps; letter-spacing: .04em; color: var(--acento); }
.relembrar[data-estado="falhou"] { border-left-color: var(--perigo); }
.relembrar-tentar { min-height: var(--alvo); min-width: var(--alvo); margin-left: .5rem; }
/* ── fim relembrar */

/* ── A fita de cetim  (spec 50 §3.5, F3) ─────────────────────────────────────
   Dois botões de 44px: o do canto do cabeçalho vivo (marca o topo, ou tira a
   fita do topo) e o pendurado na margem do parágrafo (tira aquela). A camada
   é irmã da prosa e não ocupa altura: marcar não move uma linha do texto. */
.cabecalho-vivo { padding-left: calc(var(--alvo) + 1rem); padding-right: calc(var(--alvo) + 1rem); }
.fita-marcar { position: absolute; top: 50%; right: .5rem; transform: translateY(-50%); width: var(--alvo); height: var(--alvo); min-height: var(--alvo); display: grid; place-items: center; padding: 0; border: 0; background: none; color: var(--tenue); cursor: pointer; }
.fita-marcar[aria-pressed="true"] { color: var(--acento); }
.fita-tecido { display: block; width: 12px; height: 22px; background: currentColor; clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 78%, 0 100%); }
.fitas-margem { position: relative; height: 0; }
.fita-margem { position: absolute; z-index: 5; width: var(--alvo); height: var(--alvo); min-height: var(--alvo); display: grid; justify-items: end; align-items: start; padding: 0; border: 0; background: none; color: var(--acento); cursor: pointer; }
.fita-margem .fita-tecido { height: 34px; }
.fita-margem[hidden] { display: none; }

/* ── O título do cabeçalho vivo, caminho ao frontispício  (spec 50 §3.1, F4)
   Vira <a href="/o/:id"> só em obra fatiada (Task 7); mede 44px como
   qualquer alvo de toque, herdando a cor do cabeçalho vivo. */
.cabecalho-vivo a.cabecalho-vivo-texto { display: inline-flex; align-items: center; min-height: var(--alvo); color: inherit; text-decoration: none; }

/* ── O frontispício  (spec 50 §4, F4) ────────────────────────────────────────
   A mesa em duas colunas (capa e texto) que empilham no telefone; o botão
   primário é o gesto da tela. A capa é a MESMA da estante (`.obra .capa`),
   com largura própria. Todo alvo de toque mede 44px. */
body[data-rota="obra"] main { max-width: 52rem; margin-inline: auto; }
.frontispicio { padding-block: 2rem 4rem; }
.frontispicio .mesa { display: grid; grid-template-columns: 10.5rem 1fr; gap: 1.75rem; align-items: start; }
.frontispicio .mesa-capa { width: 10.5rem; height: auto; }
.frontispicio h1 { font-family: var(--serif); font-size: 2rem; line-height: 1.15; margin: 0 0 .35rem; text-wrap: balance; }
.frontispicio .autor { font-family: var(--serif); font-size: 1.1rem; margin: 0; color: var(--tinta); }
.frontispicio :is(.tradutor, .edicao, .extensao) { font: 400 .875rem/1.4 var(--sans); color: var(--tinta-2); margin: .25rem 0 0; }
.frontispicio .continuar-obra { margin-top: 1.25rem; }
.frontispicio [data-continuar] { display: inline-flex; align-items: center; min-height: var(--alvo); text-decoration: none; }
.frontispicio .continuar-linha { font-family: var(--serif); font-style: italic; color: var(--tinta-2); margin: .6rem 0 0; }
/* Os verbos do acervo na mesa da obra (spec 64 §2.5): os mesmos círculos da
   Estante e do rodapé do artigo avulso, com o mesmo alvo de 44px. Ficam
   abaixo do «Continuar», separados por um respiro — eles são o que se faz
   com o livro, não o que se faz agora. */
.acoes-obra { flex-wrap: wrap; gap: .6rem; margin-top: 1.5rem; }
.acoes-obra .redondo { width: var(--alvo); height: var(--alvo); min-height: var(--alvo); font-size: 1.05rem; }
.frontispicio .continuar-min { font: 400 .8125rem/1.3 var(--sans); color: var(--tenue); margin: .25rem 0 0; }
.frontispicio .argumento { font-family: var(--serif); margin-top: 2rem; }
.frontispicio .sobre-edicao { margin-top: 1rem; border-top: 1px solid var(--regra); }
.frontispicio .sobre-edicao summary { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; min-height: var(--alvo); cursor: pointer; font: 500 .9375rem/1.3 var(--sans); }
.frontispicio .sobre-edicao .resumo { color: var(--tenue); font-weight: 400; }
.abas-obra { display: flex; gap: .25rem; overflow-x: auto; margin-top: 2rem; border-bottom: 1px solid var(--regra); }
.abas-obra [role="tab"] { min-height: var(--alvo); padding: 0 .9rem; border: 0; border-bottom: 2px solid transparent; background: none; color: var(--tinta-2); font: 500 .9375rem/1 var(--sans); white-space: nowrap; cursor: pointer; }
.abas-obra [role="tab"][aria-selected="true"] { color: var(--tinta); border-bottom-color: var(--acento); }
.aba-obra[hidden] { display: none; }
.aba-obra :is(ol, ul) { list-style: none; padding: 0; margin: 0; }
.parte-obra { font-variant-caps: all-small-caps; letter-spacing: .08em; color: var(--tinta-2); margin: 1.25rem 0 .25rem; }
:is(.cap-obra, .destaque-obra, .fita-obra) a { display: flex; gap: .6rem; align-items: baseline; min-height: var(--alvo); padding: .5rem 0; border-bottom: 1px solid var(--regra); color: inherit; text-decoration: none; }
.cap-obra .numeral { min-width: 2.5rem; color: var(--tenue); font-family: var(--serif); }
.cap-obra .min { margin-left: auto; color: var(--tenue); font: 400 .8125rem/1 var(--sans); }
.cap-obra .estado { min-width: 2.5rem; text-align: right; font: 500 .8125rem/1 var(--sans); color: var(--tinta-2); }
.cap-obra[data-estado="lido"] .estado { color: var(--acento); }
.grupo-obra h3 { font: 600 .875rem/1.3 var(--sans); color: var(--tinta-2); margin: 1.25rem 0 .25rem; }
.destaque-obra { border-left: 3px solid var(--regra); padding-left: .75rem; }
.destaque-obra[data-cor="roxo"] { border-left-color: var(--vivo-roxo); }
.destaque-obra[data-cor="amarelo"] { border-left-color: var(--vivo-amarelo); }
.destaque-obra[data-cor="rosa"] { border-left-color: var(--vivo-rosa); }
.destaque-obra[data-cor="azul"] { border-left-color: var(--vivo-azul); }
/* O grifo em cima, a nota embaixo (spec 50 §4.1, «grifos e notas da obra»). O `a` herda o `flex` em linha da
   lista de capítulos; com a nota ao lado, uma resposta longa do autor espremia o grifo numa coluna de uma
   palavra (15/09). A nota longa fica em quatro linhas — tocar leva ao parágrafo, onde ela está inteira. */
.destaque-obra a { flex-direction: column; align-items: stretch; gap: .3rem; }
.destaque-obra .nota { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; overflow: hidden; color: var(--tinta-2); font-size: .875rem; }
.fita-obra .numeral { min-width: 4rem; color: var(--tenue); font: 500 .8125rem/1 var(--sans); }
@media (max-width: 600px) {
  .frontispicio .mesa { grid-template-columns: 1fr; }
  .frontispicio .mesa-capa { width: 9rem; margin-inline: auto; }
}

/* ── Notas flutuantes  (spec 50 §3.4, F3) ────────────────────────────────────
   A lista do capítulo mora na prosa (é o HTML da ingestão) e fica recolhida
   por atributo no <article>; o número vem de `data-n` por `::before`, porque
   cada capítulo tem só as notas dele e a numeração do <ol> recomeçaria do 1.
   O balão é absoluto no documento, rola por dentro e nunca passa da janela.

   O número da nota usa `--tinta`, não `--tenue`: é DENTRO de `.prosa`, e o
   teste de hoje «dentro de .prosa, texto usa só --tinta» (destacável) o
   pega — diferente do numeral do capítulo (`::before` de `[data-numeral]`,
   Task 5) e do ❦ (`::after` de `hr`, Task 5), que ficam com `--tenue` de
   propósito: aqueles dois são ornamento fora do fluxo do texto, este é a
   numeração da nota que se lê. */
.prosa hr.footnotes-sep { display: none; }
.artigo[data-notas="recolhidas"] .prosa section.footnotes { display: none; }
.prosa section.footnotes { border-top: 1px solid var(--regra); margin-top: var(--space-block); padding-top: 1rem; font-size: .9em; }
.prosa section.footnotes ol { list-style: none; padding: 0; margin: 0; }
.prosa .footnote-item::before { content: attr(data-n) ". "; color: var(--tinta); font-variant-numeric: lining-nums; }
.prosa .footnote-item > p { display: inline; }
.notas-capitulo { display: block; min-height: var(--alvo); margin: 1.5rem auto 0; }
.balao-nota { position: absolute; z-index: 45; box-sizing: border-box; max-width: min(380px, 100vw - 2.5rem); overflow: auto; overscroll-behavior: contain; padding: .75rem 1rem; background: var(--papel-elev); color: var(--tinta); border: 1px solid var(--papel-borda); border-radius: 10px; box-shadow: var(--sombra-erguida); font: 400 .9375rem/1.5 var(--corpo); }
.balao-nota p { margin: 0 0 .5em; text-indent: 0; }
.balao-nota p:last-child { margin-bottom: 0; }
.balao-nota-alhures { color: var(--tenue); font-style: italic; }

/* ── A pílula Continuar  (spec 50 §4.1, F4) ─────────────────────────────────
   O segundo controle do cartão: a capa abre o frontispício, a pílula abre o
   parágrafo. Mede 44px mesmo onde os botões redondos do cartão medem 30. */
:is(.obra, .coluna-capa) > .continuar { display: inline-flex; align-items: center; justify-content: center; align-self: flex-start; min-height: var(--alvo); margin-top: .35rem; padding: 0 .9rem; border-radius: 999px; background: var(--acento); color: var(--sobre-acento); font: 600 .8125rem/1 var(--sans); text-decoration: none; }

/* ── quem é (spec 50 §5.4) ────────────────────────────────────────────────── */
.ficha-personagem {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  max-height: 70vh;
  overflow: auto;
  padding: 1rem 1.25rem 1.5rem;
  background: var(--papel);
  color: var(--tinta);
  border-top: 1px solid var(--papel-borda);
  border-radius: var(--raio) var(--raio) 0 0;
  font-family: var(--sans);
  z-index: 60;
}
/* `.ficha-personagem` reusa a classe `.sheet` (molde comum de nota/conversa/
   colar/metadados), mas é bandeja INFERIOR de largura total — não a coluna
   centrada em `left: 50%` que aquele molde presume. Sem este `transform:
   none`, a regra `.sheet[data-aberto="sim"] { transform: translate(-50%, 0) }`
   deslocaria a bandeja meia tela para a esquerda ao abrir (o `left: 0` daqui
   já não deixa margem para o `-50%` descontar). Mesmo remédio que `#ajustes`
   e `#sumario`, os outros dois sheets de largura total da casa. */
.ficha-personagem[data-aberto="sim"] { transform: none; }
.ficha-personagem .fechar-ficha { float: right; min-height: var(--alvo); min-width: var(--alvo); }
.ficha-revelacoes, .ficha-relacoes { padding-left: 1.2rem; }
.ficha-alcance { color: var(--acento); font-size: .85rem; }
/* ── fim quem é */

/* ── memória da obra no frontispício (spec 50 §5.1, §4.2) ───────────────────── */
.frontispicio-memoria { font-family: var(--sans); font-size: .85rem; color: var(--tinta); }
.frontispicio-memoria[data-estado="falhou"] .memoria-frase { color: var(--perigo); }
.memoria-tentar, .esquecer-conversa .btn { min-height: var(--alvo); }
.sessao-excluir { min-height: var(--alvo); }
.personagens-obra, .sessoes-obra { list-style: none; padding: 0; }
.personagem-obra { padding: .45rem 0; border-bottom: 1px solid var(--papel-borda); }
/* A aba Conversa (15/09): sem regra própria, o resumo saía como um bloco corrido do tamanho do texto do
   livro, os títulos das sessões no azul sublinhado do navegador e o Excluir como botão escuro ao lado de
   cada linha. Rótulo pequeno por seção; o resumo recuado por um fio da cor da obra; a sessão em uma linha
   (tipo · título em até duas linhas · Excluir discreto, que só se acende no toque que confirma). */
.rotulo-conversa { font: 600 .6875rem/1.2 var(--sans); letter-spacing: .1em; text-transform: uppercase; color: var(--tenue); margin: 1.75rem 0 .6rem; }
.resumo-conversa { font-family: var(--serif); color: var(--tinta); }
.resumo-conversa > p:not(.turnos-lembrados) { margin: 0; max-width: 62ch; font-size: 1rem; line-height: 1.65; color: var(--tinta-2); border-left: 2px solid var(--acento); padding-left: 1rem; }
.turnos-lembrados { margin: .6rem 0 0; font: 400 .8125rem/1.3 var(--sans); color: var(--tenue); }
.sessoes-obra { list-style: none; padding: 0; margin: 0; }
.sessao-obra { display: flex; align-items: center; gap: .75rem; padding: .2rem 0; border-bottom: 1px solid var(--papel-borda); }
.sessao-link { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: .75rem; min-height: var(--alvo); padding: .45rem 0; color: inherit; text-decoration: none; }
.sessao-obra .tipo { flex: 0 0 4.25rem; font: 600 .6875rem/1 var(--sans); letter-spacing: .08em; text-transform: uppercase; color: var(--acento); }
.sessao-titulo { font: 400 .9375rem/1.4 var(--serif); color: var(--tinta); display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
a.sessao-link:hover .sessao-titulo { text-decoration: underline; text-decoration-color: var(--papel-borda); }
.btn.sessao-excluir { flex: none; background: transparent; border: 1px solid transparent; box-shadow: none; color: var(--tenue); }
.btn.sessao-excluir:hover, .btn.sessao-excluir[data-confirmar="sim"] { color: var(--perigo); border-color: currentColor; }
.esquecer-conversa { margin-top: 2rem; }
.resumo-estado[data-estado="falhou"], .conversa-esquecida, .sessao-excluida, .sessao-motivo { color: var(--perigo); font-family: var(--sans); font-size: .85rem; }
/* ── fim memória da obra no frontispício */
/* ═════════════════════════════════════════════════════════════════════════
   O ACERVO DE DECISÕES  (spec 51 §6.2, fase F4)

   A ficha de decisão de cada estudo técnico, e o lugar de uso dela:
   `/decisoes`, dentro da seção da escrivaninha. Bloco próprio, no fim do
   arquivo, só com tokens — os três temas vêm de graça, e o teste do acervo
   recusa cor crua aqui dentro.

   Os controles passam o `--alvo` de 44px: o filtro e a força são tocados no
   iPad, com o dedo, e um chip de 24px é o controle que se erra.
   ═════════════════════════════════════════════════════════════════════════ */
.cabeca-escrivaninha {
  display: flex; align-items: center; justify-content: space-between;
  gap: .4rem .8rem; flex-wrap: wrap;
}
.cabeca-escrivaninha .link-decisoes, .cabeca-decisoes .voltar-escrivaninha {
  flex: none; min-height: var(--alvo); display: inline-flex; align-items: center;
  text-decoration: none;
}

.decisoes { max-width: var(--measure); margin: 0 auto 3rem; padding: 0 1.1rem; }

.filtros-decisoes {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
  gap: .6rem .8rem; margin: .6rem 0 1rem;
}
.filtros-decisoes label {
  display: flex; flex-direction: column; gap: .25rem;
  font-family: var(--sans); font-size: .72rem; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; color: var(--tenue);
}
.filtros-decisoes select, .filtros-decisoes input[type="search"] {
  min-height: var(--alvo); box-sizing: border-box; width: 100%;
  font-family: var(--sans); font-size: .95rem; letter-spacing: 0; text-transform: none;
  color: var(--tinta); background: var(--papel-elev);
  border: 1px solid var(--borda-controle); border-radius: 10px; padding: 0 .7rem;
}
/* O Safari desenha o `<select>` nativo com 24px e IGNORA o `min-height` —
   medido pela bancada de design em 14/09, com o teste de CSS verde. Sem a
   aparência nativa ele obedece, e a seta volta desenhada pelo rótulo (sem
   imagem: a CSP não aceita `data:` em `img-src`). */
.filtros-decisoes select { -webkit-appearance: none; appearance: none; padding-right: 2rem; }
.filtros-decisoes label { position: relative; }
.filtros-decisoes label:not(.busca-decisoes)::after {
  content: "▾"; position: absolute; right: .75rem; bottom: 0; height: var(--alvo);
  display: flex; align-items: center; pointer-events: none;
  font-size: .9rem; color: var(--tinta-2); letter-spacing: 0;
}
.filtros-decisoes select:focus-visible, .filtros-decisoes input:focus-visible {
  outline: 2px solid var(--foco); outline-offset: 1px;
}
.filtros-decisoes .busca-decisoes { grid-column: 1 / -1; }

.aviso-decisoes {
  font-family: var(--sans); font-size: .84rem; color: var(--tinta-2);
  border-left: 3px solid var(--acento); padding: .4rem .7rem; margin: .4rem 0;
}
.conta-decisoes {
  display: flex; align-items: center; flex-wrap: wrap; gap: .4rem .7rem;
  font-family: var(--sans); font-size: .82rem; color: var(--tenue); margin: 0 0 .8rem;
}
.conta-decisoes .limpar, .resultado-decisoes .vazio .btn { min-height: var(--alvo); }
/* Voltar e limpar são gestos SECUNDÁRIOS: a primeira captura (14/09) os
   mostrou como os dois blocos mais escuros da tela, acima das próprias fichas. */
.cabeca-decisoes .voltar-escrivaninha, .cabeca-escrivaninha .link-decisoes, .resultado-decisoes [data-limpar] {
  background: transparent; color: var(--tinta); border: 1px solid var(--borda-controle); box-shadow: none;
}

.lista-decisoes { list-style: none; margin: 0; padding: 0; }
.decisao {
  position: relative; background: var(--papel-elev);
  border: 1px solid var(--papel-borda-fina); border-radius: 14px;
  box-shadow: var(--sombra-erguida);
  padding: 1rem 1.1rem .6rem 1.3rem; margin-bottom: .9rem;
}
/* A lombada no acento: a ficha é da escrivaninha, e fala a língua da ficha
   de estudo que mora ao lado. */
.decisao::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px; border-radius: 14px 0 0 14px; background: var(--acento);
}
.decisao.em-foco { outline: 2px solid var(--foco); outline-offset: 3px; }
.decisao header {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: 0 .8rem;
}
.decisao h2 {
  font-family: var(--corpo); font-size: 1.14rem; line-height: 1.3; font-weight: 600;
  color: var(--tinta); margin: 0; flex: 1 1 18rem;
}
.decisao h2:focus { outline: none; }
.decisao .origem {
  min-height: var(--alvo); display: inline-flex; align-items: center;
  font-family: var(--sans); font-size: .8rem; color: var(--tenue);
  text-underline-offset: 3px;
}
.decisao .origem:hover, .decisao .origem:focus-visible { color: var(--acento); }

.decisao .etiquetas { display: flex; flex-wrap: wrap; gap: .3rem; margin: .45rem 0 .55rem; }
.decisao .chip {
  display: inline-flex; align-items: center; line-height: 1.2;
  font-family: var(--sans); font-size: .74rem; padding: .22rem .6rem;
  border-radius: 999px; border: 1px solid var(--papel-borda);
  color: var(--tinta-2); background: transparent;
}
.decisao .chip.onde { color: var(--acento); border-color: var(--acento); font-weight: 600; }

.decisao .escolha { font-family: var(--corpo); color: var(--tinta); margin: 0 0 .35rem; }
.decisao .escolha .rotulo, .fecho-fichas .rotulo {
  font-family: var(--sans); font-size: .68rem; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--tenue); margin-right: .35rem;
}
.decisao .contexto { font-family: var(--sans); font-size: .88rem; color: var(--tinta-2); margin: 0 0 .55rem; }

.decisao .forcas { list-style: none; margin: 0 0 .3rem; padding: 0; display: flex; flex-wrap: wrap; gap: .35rem; }
.decisao .chip.forca {
  min-height: var(--alvo); padding: 0 .85rem; font-size: .84rem; cursor: pointer;
  color: var(--tinta); border-color: var(--borda-controle);
}
.decisao .chip.forca:hover, .decisao .chip.forca:focus-visible {
  color: var(--acento); border-color: var(--acento); outline: none;
}

.decisao details > summary {
  min-height: var(--alvo); display: flex; align-items: center; gap: .45rem;
  list-style: none; cursor: pointer;
  font-family: var(--sans); font-size: .84rem; font-weight: 600; color: var(--tinta-2);
}
.decisao details > summary::-webkit-details-marker { display: none; }
.decisao details > summary::before {
  content: "▸"; font-size: .8em; transition: transform var(--dur-rapida) var(--curva);
}
.decisao details[open] > summary::before { transform: rotate(90deg); }
.decisao details > summary:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; border-radius: 6px; }
.decisao dl { margin: 0 0 .6rem; font-family: var(--sans); font-size: .88rem; }
.decisao dt { font-weight: 600; color: var(--tinta); margin-top: .5rem; }
.decisao dd { margin: .15rem 0 0; color: var(--tinta-2); }
.decisao dd ul { margin: 0; padding-left: 1.1rem; }

/* «Mesma força»: o fio entre fichas de estudos diferentes. Separada por uma
   regra, porque ela não é mais um campo da ficha — é a ficha olhando para
   fora dela. */
.decisao .mesma-forca { border-top: 1px solid var(--regra); margin-top: .2rem; }
.decisao .mesma-forca ul { list-style: none; margin: 0 0 .4rem; padding: 0; }
.decisao .mesma-forca li { display: flex; flex-wrap: wrap; align-items: center; gap: 0 .6rem; }
.decisao .mesma-forca .vizinha {
  min-height: var(--alvo); padding: 0; border: 0; background: none; cursor: pointer;
  font-family: var(--corpo); font-size: .98rem; text-align: left; color: var(--acento);
  text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px;
}
.decisao .mesma-forca .vizinha:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; border-radius: 4px; }
.decisao .mesma-forca .via { font-family: var(--sans); font-size: .76rem; color: var(--tenue); }
.decisao .mesma-forca.vazia {
  font-family: var(--sans); font-size: .8rem; color: var(--tenue);
  margin: .2rem 0 .4rem; padding-top: .6rem;
}

/* A ficha no fecho do estudo: a lista curta, e o caminho até o acervo. */
.fecho-fichas .fichas-do-estudo { list-style: none; padding: 0; margin: .4rem 0 .9rem; }
.fecho-fichas .fichas-do-estudo li {
  display: flex; flex-direction: column; gap: .15rem;
  padding: .6rem 0; border-bottom: 1px solid var(--regra);
}
.fecho-fichas .fichas-do-estudo strong { font-family: var(--corpo); color: var(--tinta); }
.fecho-fichas .fichas-do-estudo .escolha { font-family: var(--sans); font-size: .9rem; color: var(--tinta-2); }
.fecho-fichas .via { font-family: var(--sans); font-size: .76rem; color: var(--tenue); }
.fecho-fichas .btn { min-height: var(--alvo); }

@media (max-width: 640px) {
  .filtros-decisoes { grid-template-columns: 1fr; }
}

/* ── O laboratório de DECISÃO  (spec 51 §5.2) ──────────────────────────────
   Um painel sobre o documento do lab, entre a abertura e a primeira seção. O
   que se toca são os segmentados — valores fechados, a vigente acesa, cada
   opção com o `--alvo` do núcleo nos dois eixos —, e o que se lê é a tabela
   das rodadas, onde o trade-off aparece comparando linhas.

   Tudo sob `.prosa .lab-decisao`: o painel mora DENTRO da prosa, e as regras
   de `h2`, `table` e `ul` da leitura venceriam uma classe solta — a tabela de
   rodadas sairia com a moldura das tabelas do texto, e o título do painel
   com o tamanho de seção. E a tinta é SÓ `--tinta`, como toda regra sob
   `.prosa` (`nucleo.test.mjs`): a hierarquia sai do corpo, do peso e da caixa
   alta, não de tinta secundária. Nenhum campo de texto aqui, de propósito: zero
   digitação e nenhuma previsão (spec 51 §10). */
.prosa .lab-decisao {
  margin: 1.6rem 0 2.2rem; padding: 1.1rem 1.2rem 1.2rem;
  border: 1px solid var(--borda-controle); border-radius: 14px;
  background: var(--papel-elev); font-family: var(--sans);
  max-width: 100%; box-sizing: border-box;
}
.prosa .lab-decisao h2 {
  font-family: var(--sans); font-size: .74rem; line-height: 1.3; letter-spacing: .09em;
  text-transform: uppercase; color: var(--tinta); margin: 0 0 .9rem; font-weight: 600;
}
.prosa .lab-decisao .parametros-decisao { display: flex; flex-direction: column; gap: .8rem; }
.prosa .lab-decisao .parametro-decisao {
  display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .9rem;
}
.prosa .lab-decisao .parametro-decisao .rotulo {
  flex: 0 0 9.5rem; font-size: .88rem; font-weight: 600; color: var(--tinta); line-height: 1.3;
}
/* Mesma construção do segmentado do motor da voz: o campo por fora, as
   pílulas por dentro com 2px de folga, e o raio de dentro é o de fora menos
   a folga. `flex-wrap` porque quatro valores longos numa coluna de iPad em
   retrato não cabem numa linha, e pílula cortada não é alvo. */
.prosa .lab-decisao .segmentado {
  display: inline-flex; flex-wrap: wrap; padding: 2px; gap: 2px; max-width: 100%;
  background: var(--papel-elev-2); border: 1px solid var(--borda-controle);
  border-radius: var(--raio-p);
}
.prosa .lab-decisao .opcao {
  min-height: var(--alvo); min-width: var(--alvo); padding: 0 .9rem; margin: 0;
  font-family: var(--sans); font-size: .86rem; line-height: 1;
  color: var(--tinta); background: none; border: 0;
  border-radius: calc(var(--raio-p) - 2px); cursor: pointer; white-space: nowrap;
}
/* Acento cheio com `--sobre-acento`, nunca `#fff` — o motivo é o do motor da voz. */
.prosa .lab-decisao .opcao[aria-checked="true"] {
  background: var(--acento); color: var(--sobre-acento); font-weight: 600;
}
.prosa .lab-decisao .opcao:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }
.prosa .lab-decisao .opcao .padrao { opacity: .7; }
.prosa .lab-decisao .rodar-decisao {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; margin: 1.1rem 0 .9rem;
}
.prosa .lab-decisao .rodar-combinacao { min-height: var(--alvo); margin: 0; }
.prosa .lab-decisao .estado-decisao { margin: 0; font-size: .86rem; line-height: 1.4; color: var(--tinta); }
/* A tabela rola na PRÓPRIA caixa: três parâmetros e quatro métricas numa
   coluna estreita passam da largura, e quem rola não pode ser a página. */
.prosa .lab-decisao .tabela-decisao { overflow-x: auto; max-width: 100%; }
.prosa .lab-decisao table {
  width: 100%; border-collapse: collapse; margin: 0; border: 0;
  font-family: var(--sans); font-size: .88rem; font-variant-numeric: tabular-nums;
  background: none; box-shadow: none;
}
.prosa .lab-decisao th, .prosa .lab-decisao td {
  padding: .5rem .6rem; border: 0; border-bottom: 1px solid var(--regra);
  text-align: left; vertical-align: bottom; color: var(--tinta); background: none;
}
.prosa .lab-decisao thead th { font-size: .74rem; font-weight: 600; color: var(--tinta); line-height: 1.25; }
.prosa .lab-decisao .unidade { display: block; font-weight: 400; }
.prosa .lab-decisao .metrica { text-align: right; }
.prosa .lab-decisao th.n { width: 2rem; color: var(--tinta); font-weight: 600; }
.prosa .lab-decisao tr.escolhida td, .prosa .lab-decisao tr.escolhida th { background: var(--papel-elev-2); }
.prosa .lab-decisao tr.ultima th.n { color: var(--acento); }
.prosa .lab-decisao td.erro { color: var(--perigo); font-size: .84rem; }
.prosa .lab-decisao tr.vazia td { color: var(--tinta); font-size: .86rem; }
.prosa .lab-decisao .leituras-decisao:empty { display: none; }
.prosa .lab-decisao .leituras-decisao h3 {
  font-family: var(--sans); font-size: .74rem; letter-spacing: .09em; text-transform: uppercase;
  color: var(--tinta); margin: 1.1rem 0 .5rem; font-weight: 600;
}
.prosa .lab-decisao .leituras-decisao ul { margin: 0; padding-left: 1.1rem; }
.prosa .lab-decisao .leituras-decisao li {
  font-family: var(--corpo); font-size: .96rem; line-height: 1.5; color: var(--tinta); margin: 0 0 .35rem;
}
/* O cabeçalho quebra por palavra, nunca no meio dela: «Répli-cas» vinha da
   hifenização da prosa, que aqui só atrapalha a leitura da coluna. */
.prosa .lab-decisao th { hyphens: manual; -webkit-hyphens: manual; }

/* ── A língua do Leitor  (spec 53 §5.2–5.4) ────────────────────────────────
   Quatro peças que qualquer tela usa: o aviso de erro, o processo em
   andamento, a barra de desfazer e a folha de custo. A régua é a de TDAH e
   dislexia: frase visível, nada animado puxando a atenção, alvo de 44px,
   contraste da tinta do corpo e nunca só cor. */

.aviso-erro { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem;
  font: 400 .9375rem/1.5 var(--sans); color: var(--tinta); }
.aviso-erro-frase { margin: 0; flex: 1 1 16rem; }
.aviso-erro-frase > span:first-child { font-weight: 600; }
.aviso-erro-tentar { min-height: 44px; }
.aviso-erro-detalhe { flex: 1 0 100%; font-size: .8rem; color: var(--tenue); }
.aviso-erro-detalhe summary { cursor: pointer; min-height: 32px; display: inline-flex; align-items: center; }
.aviso-erro-detalhe code { font-family: var(--mono); word-break: break-word; }

.processo { display: flex; flex-wrap: wrap; align-items: baseline; gap: .15rem .6rem;
  font: 400 .9375rem/1.45 var(--sans); color: var(--tinta); }
.processo-frase { font-weight: 600; }
.processo-tempo { color: var(--tinta-2); font-variant-numeric: tabular-nums; }
.processo-sair { flex-basis: 100%; color: var(--tinta-2); font-size: .85rem; }
.processo[data-processo="demorando"] .processo-tempo { color: var(--tinta); }
.processo-tentar, .processo-acao { min-height: 44px; }

.desfazer { position: fixed; z-index: 70; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--barra-h) + .75rem);
  /* Largura PRÓPRIA (L-323): centrada por `left: 50%`, a caixa sem ela
     encolhia para caber na metade da tela, e a frase longa do «Puxado…» saiu
     no iPhone com 195 px e 16 linhas, quebrada no meio da palavra. O teto de
     40rem é a medida de uma frase que se lê de uma vez: sem ele, a mesma
     frase ia a 1.168 px no Mac. */
  box-sizing: border-box; width: max-content; max-width: min(calc(100vw - 2rem), 40rem);
  display: flex; align-items: center; gap: 1rem; padding: .35rem .5rem .35rem 1rem;
  background: var(--tinta); color: var(--papel); border-radius: 12px; box-shadow: var(--sombra-erguida);
  font: 500 .9375rem/1.4 var(--sans); }
.desfazer-frase { overflow-wrap: anywhere; }
.desfazer-botao { flex: none; min-height: 44px; min-width: 44px; padding: 0 .9rem; border: 0; border-radius: 8px;
  background: transparent; color: var(--papel); font: 700 .9375rem/1 var(--sans); text-decoration: underline;
  text-underline-offset: 3px; cursor: pointer; }
.desfazer-botao:focus-visible { outline: 2px solid var(--papel); outline-offset: 2px; }
/* Na lateral do Mac a nota se centra na ÁREA ÚTIL, não na janela: centrada
   na janela, a frase longa entrava 79 px na lateral de 236 (L-323), em toda
   `.desfazer` e `.aviso-mandado` do app. E só aqui ela desce ao chão: sem
   `pointer: fine` (o iPad deitado, 1.180 px) a barra continua embaixo, e o
   `bottom` de 1,5rem punha a nota por cima dela. */
@media (min-width: 1100px) and (pointer: fine) {
  .desfazer { bottom: 1.5rem; left: calc(50% + 118px); max-width: min(calc(100vw - 236px - 2rem), 40rem); }
}

.custo-fundo { position: fixed; inset: 0; z-index: 80; display: grid; place-items: end center;
  background: color-mix(in srgb, var(--tinta) 35%, transparent); padding: 1rem; }
@media (min-width: 40rem) { .custo-fundo { place-items: center; } }
.custo { box-sizing: border-box; width: min(28rem, 100%); padding: 1.25rem; border-radius: 14px;
  background: var(--papel-elev); color: var(--tinta); border: 1px solid var(--papel-borda);
  box-shadow: var(--sombra-erguida); padding-bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px)); }
.custo-frase { margin: 0 0 1rem; font: 400 1rem/1.5 var(--sans); }
.custo-botoes { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .5rem; }
.custo-botoes .btn { min-height: 44px; padding: 0 1rem; font-size: .9375rem; }

/* O estado da fila no cabeçalho (§5.3): só aparece quando há o que dizer. */
.fila-estado { font: 500 .8rem/1.3 var(--sans); color: var(--tinta-2); }
.fila-estado[data-fila="bloqueada"] { color: var(--perigo); }
.fila-estado:empty { display: none; }

/* O subtítulo do destino na lateral do Mac («seus estudos», spec 53 §5.1).
   Classe e não `style=`: a CSP do app não deixa passar estilo inline. */
#barra-nav .nav-sub small { font-size: 11px; font-weight: 400; opacity: .85; }

/* ── O glifo de pausa desenhado, no meio de uma linha de texto  (16/09) ─────
   Na cápsula o botão é flex e centra sozinho; no «Pausar» do cabeçalho e no
   transporte o SVG senta na linha de base e fica alto demais. O deslocamento
   é o de um ícone de 1em sobre texto de x-height comum. */
svg[data-glifo="pausa"] { vertical-align: -.14em; }

/* ── O boletim não lido (spec 62) ── */
/* Um ponto no ícone do destino Notícias quando alguma gazeta tem edição que a
   pessoa ainda não abriu. Ponto e não número: os números saíram dos destinos
   em 04/09. `--cromo-acento` porque o campo é grafite nos dois modos (o mesmo
   motivo do ícone do ativo). O anel de cromo em volta separa o ponto do traço
   do ícone quando os dois se tocam. Forma, e não só cor: quem não distingue o
   acento ainda vê um círculo cheio onde o ícone não tem. */
#barra-nav a[data-novo] .ic { position: relative; }
#barra-nav a[data-novo] .ic::after {
  content: ""; position: absolute; top: -2px; right: -4px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--cromo-acento);
  box-shadow: 0 0 0 2px var(--cromo-1);
}
/* A linha que diz QUAL: só na lateral. Na barra do telefone cada destino é
   uma coluna de 58px, e uma terceira linha empurraria a barra inteira — ali
   fica o ponto, e o nome vai no rótulo de acessibilidade. */
.nav-aviso { display: none; }
@media (min-width: 1100px) and (pointer: fine) {
  #barra-nav .nav-aviso { display: inline; }
  #barra-nav .nav-aviso small {
    font-size: 11px; font-weight: 400; color: var(--cromo-tenue);
  }
}
/* O ponto no título da gazeta, quando ela é a única (com várias, vai no texto
   da opção do seletor). */
.ponto-novo {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: var(--acento); vertical-align: middle; margin-left: .35em;
}
/* ── fim do boletim não lido ── */

/* ── Notícias (spec 59) ── */
/* ═══════════════════════════════════════════════════════════════════════════
   O destino «Notícias»: a casca, o Boletim, o Feed, as Fontes e os Ajustes
   (spec 59 §4 · L-309). Bloco próprio, no fim do arquivo, só com tokens — os
   três temas vêm de graça, e o teste das Notícias recusa cor crua e token
   que não existe aqui dentro.

   A régua é a do app, e não uma nova: título em serifa, navegação em sans,
   superfícies do núcleo, alvo de 44px em tudo que se toca. O único gesto
   próprio é o NÚMERO do Boletim — o `n` do contrato pendurado na margem,
   em algarismo de texto e na cor do acento. A edição é uma sequência
   numerada de verdade (o `n` é contínuo de ponta a ponta, §8), e é o número
   que a pessoa usa para voltar a um item («o 7 de ontem»); por isso ele
   ganha a margem, e o resto da página fica quieto em volta.
   ═════════════════════════════════════════════════════════════════════════ */

/* O Feed precisa da coluna de seções AO LADO da lista no iPad e no Mac; a
   medida de leitura sozinha não comporta as duas. A prosa do Boletim, dos
   Ajustes e das Fontes continua na medida (ver as telas abaixo). */
body[data-rota^="noticias"] main { max-width: calc(var(--measure) + 14rem); }

/* O filete das listas. O `--regra` do núcleo é desenhado para a FOLHA
   (`--papel`), e as listas das Notícias moram na MESA (`--tela`): no tema
   claro, `--regra` #e6e2d9 sobre `--tela` #e8e2d7 dá contraste 1,0 — o Feed
   de 138 linhas por dia saía sem uma divisória visível (Safari, L-310). A
   tinta a 14% sobre transparente vale nas duas superfícies e nos três temas,
   porque compõe com o que estiver embaixo. */
.noticias { --regra-mesa: color-mix(in srgb, var(--tinta) 14%, transparent); }

/* ── A casca ─────────────────────────────────────────────────────────────── */
.cabeca-noticias {
  display: flex; align-items: center; flex-wrap: wrap; gap: .35rem .9rem; margin: 0 0 .9rem;
}
.cabeca-noticias .titulo-tela { margin: 0; }
.gazeta-titulo {
  margin: 0; font-family: var(--serif); font-style: italic; font-size: 1.3rem;
  line-height: 1.25; color: var(--tinta-2);
}
.gazeta-escolha { position: relative; }
.gazeta-escolha select {
  -webkit-appearance: none; appearance: none; min-height: var(--alvo); box-sizing: border-box;
  font-family: var(--serif); font-style: italic; font-size: 1.15rem; color: var(--tinta);
  background: var(--papel-elev); border: 1px solid var(--borda-controle); border-radius: 10px;
  padding: 0 2rem 0 .75rem; cursor: pointer;
}
.engrenagem {
  margin-left: auto; flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: var(--alvo); height: var(--alvo); border-radius: var(--raio-p); color: var(--tinta-2);
}
.engrenagem svg { width: 22px; height: 22px; }
.engrenagem:hover, .engrenagem:focus-visible { color: var(--acento); }
.engrenagem[aria-current] { color: var(--tinta); background: var(--papel-elev-2); }
.abas-config { margin-top: -.4rem; }
/* O segmentado do app nasceu para a inbox, com 38px; aqui ele é a navegação
   principal do destino, tocado a cada troca de vista, e a régua das Notícias
   é o alvo de 44 (medido no Safari, L-310: 38 nas duas fileiras de abas). */
.abas.seg:is(.abas-noticias, .abas-config) .aba { min-height: var(--alvo); box-sizing: border-box; }

.noticias .btn {
  min-height: var(--alvo); display: inline-flex; align-items: center; justify-content: center;
  gap: .4rem; text-decoration: none; box-sizing: border-box;
}
.noticias .botoes { display: flex; flex-wrap: wrap; gap: .5rem; }
.noticias :is(input:not([type="radio"]):not([type="checkbox"]):not([type="file"]), textarea, select):focus-visible,
.noticias :is(a, button):focus-visible {
  outline: 2px solid var(--foco); outline-offset: 2px;
}

/* Os campos: o mesmo aro dos filtros das decisões — sobre `--tela`, a borda
   `--borda-controle` é a única pista de que isto é um campo. */
.noticias :is(input[type="text"], input:not([type]), input[type="search"], input[type="number"],
  input[type="date"], input[type="time"], textarea, select):not(.gazeta-escolha select) {
  min-height: var(--alvo); box-sizing: border-box; width: 100%;
  font-family: var(--sans); font-size: .95rem; color: var(--tinta);
  background: var(--papel-elev); border: 1px solid var(--borda-controle); border-radius: 10px;
  padding: 0 .7rem;
}
.noticias textarea { padding: .6rem .7rem; line-height: 1.5; resize: vertical; }
/* O `<select>` nativo do Safari ignora o `min-height` (medido em 14/09 nas
   decisões): sem a aparência nativa ele obedece, e a seta volta desenhada
   pelo rótulo — a CSP não aceita `data:` numa imagem de fundo. */
.noticias select { -webkit-appearance: none; appearance: none; padding-right: 2rem; }
.noticias label:has(> select) { position: relative; }
.noticias label:has(> select)::after {
  content: "▾"; position: absolute; right: .75rem; bottom: 0; height: var(--alvo);
  display: flex; align-items: center; pointer-events: none; font-size: .9rem; color: var(--tinta-2);
}
.noticias label > span:first-child:not(.so-leitor) {
  display: block; margin: 0 0 .25rem; font-family: var(--sans); font-size: .78rem; font-weight: 600;
  color: var(--tinta-2);
}
.noticias .gazeta-escolha > span:first-child { display: none; }

.aviso-noticias {
  font-family: var(--sans); font-size: .84rem; color: var(--tinta-2);
  border-left: 3px solid var(--acento); padding: .4rem .7rem; margin: .2rem 0 .9rem;
}
.recado-noticias {
  font-family: var(--sans); font-size: .9rem; line-height: 1.5; color: var(--tinta);
  background: var(--papel-elev); border: 1px solid var(--papel-borda); border-radius: var(--raio);
  padding: .7rem .9rem; margin: 0 0 1rem;
}
.recado-noticias p { margin: 0; }
.recado-noticias summary { min-height: var(--alvo); display: flex; align-items: center; cursor: pointer; color: var(--tinta-2); }
.noticias .url { font-family: var(--mono); font-size: .8rem; overflow-wrap: anywhere; }

/* ── Os modelos: sem gazeta, a tela oferece por onde começar ─────────────── */
.modelos-intro { max-width: var(--measure); font-size: .9rem; line-height: 1.5; }
.modelos {
  list-style: none; margin: 1rem 0 2rem; padding: 0;
  display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
}
.modelo {
  display: flex; flex-direction: column; gap: .5rem; padding: 1.1rem 1.2rem 1rem;
  background: var(--papel-elev); border: 1px solid var(--papel-borda-fina); border-radius: 14px;
  box-shadow: var(--sombra-erguida);
}
.modelo h2 { font-family: var(--serif); font-size: 1.25rem; line-height: 1.2; font-weight: 600; margin: 0; }
.modelo-descricao { font-family: var(--serif); font-size: .98rem; line-height: 1.45; margin: 0; color: var(--tinta); }
.modelo-meta { font-family: var(--sans); font-size: .8rem; line-height: 1.45; color: var(--tinta-2); margin: 0; }
.modelo-acao { margin-top: auto; padding-top: .3rem; display: grid; gap: .5rem; }

/* ── O Feed ──────────────────────────────────────────────────────────────── */
.feed-grade { display: grid; grid-template-columns: minmax(0, 1fr); gap: .7rem; }
/* Abaixo de 40rem, as seções são a fileira de fichas rolável da barra do
   telefone; acima, uma coluna ao lado que fica parada enquanto a lista rola. */
.secoes-feed {
  display: flex; gap: .4rem; overflow-x: auto; scrollbar-width: none; padding-bottom: .15rem;
  font-family: var(--sans);
}
.secoes-feed::-webkit-scrollbar { display: none; }
.secao-feed {
  flex: none; min-height: var(--alvo); display: inline-flex; align-items: center; box-sizing: border-box;
  padding: 0 .9rem; border: 1px solid var(--borda-controle); border-radius: 999px;
  background: var(--papel-elev); color: var(--tinta-2); text-decoration: none;
  font-size: .84rem; font-weight: 500; white-space: nowrap;
}
.secao-feed:hover { color: var(--acento); }
.secao-feed[aria-current] {
  color: var(--tinta); font-weight: 600; border-color: var(--acento);
  background: color-mix(in srgb, var(--acento) 10%, var(--papel-elev));
}
@media (min-width: 40rem) {
  .feed-grade { grid-template-columns: 11rem minmax(0, 1fr); gap: 1.5rem; align-items: start; }
  .secoes-feed {
    flex-direction: column; gap: .1rem; overflow: visible; position: sticky; top: 1rem;
  }
  .secao-feed {
    border: 0; background: none; border-radius: var(--raio-p); padding: .55rem .75rem;
    white-space: normal; line-height: 1.3;
  }
  .secao-feed[aria-current] { background: var(--papel-elev-2); box-shadow: inset 3px 0 0 var(--acento); }
}

.ferramentas-feed { display: flex; gap: .5rem; align-items: center; margin: 0 0 .4rem; }
.busca-feed { flex: 1; margin: 0; }
.ferramentas-feed [data-selecionar][aria-pressed="true"] { color: var(--acento); border-color: var(--acento); }

.feed { list-style: none; margin: 0; padding: 0; }
.feed ul { list-style: none; margin: 0; padding: 0; }
.dia-feed h2 {
  display: flex; align-items: center; gap: .6rem; margin: 1.3rem 0 .2rem;
  font-family: var(--sans); font-size: .8rem; font-weight: 600; color: var(--tinta-2);
}
.dia-feed:first-child h2 { margin-top: .6rem; }
.dia-feed h2::after { content: ""; flex: 1; border-top: 1px solid var(--regra-mesa); }

.item-feed { display: grid; grid-template-columns: minmax(0, 1fr); border-bottom: 1px solid var(--regra-mesa); }
.feed.selecionando .item-feed { grid-template-columns: var(--alvo) minmax(0, 1fr); }
.feed.selecionando .item-feed > :not(.marcar-feed) { grid-column: 2; }
.marcar-feed { display: flex; align-items: flex-start; justify-content: center; padding-top: .85rem; cursor: pointer; }
.marcar-feed input { width: 1.15rem; height: 1.15rem; margin: 0; accent-color: var(--acento); }

.linha-feed {
  -webkit-appearance: none; appearance: none; background: none; border: 0; margin: 0;
  width: 100%; min-height: var(--alvo); box-sizing: border-box; padding: .7rem .15rem;
  display: grid; gap: .15rem; text-align: left; color: var(--tinta); font: inherit; cursor: pointer;
}
.linha-feed:hover .titulo { color: var(--acento); }
.linha-feed:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; border-radius: var(--raio-p); }
.linha-feed .meta {
  font-family: var(--sans); font-size: .74rem; color: var(--tenue); font-variant-numeric: tabular-nums;
}
.linha-feed .titulo { font-family: var(--serif); font-size: 1.02rem; line-height: 1.35; font-weight: 600; }
/* Uma linha de resumo, e não mais: a lista é para varrer. O inteiro abre no lugar. */
.linha-feed .resumo {
  font-family: var(--sans); font-size: .84rem; color: var(--tinta-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.item-feed.aberto .linha-feed .resumo { display: none; }
.aberta-feed { padding: 0 .15rem .9rem; }
.resumo-inteiro {
  font-family: var(--corpo, var(--serif)); font-size: .98rem; line-height: 1.55; color: var(--tinta); margin: 0 0 .7rem;
}
.acoes-feed { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.item-feed > .enviada { justify-self: start; margin: -.35rem 0 .6rem .15rem; }
.noticias .enviada {
  display: inline-flex; align-items: center; gap: .35rem;
  font-family: var(--sans); font-size: .76rem; font-weight: 600; color: var(--tinta-2);
}
.noticias .enviada::before { content: "✓"; color: var(--acento); }
.noticias .enviando { font-family: var(--sans); font-size: .8rem; color: var(--tinta-2); }
.noticias .erro-envio { font-family: var(--sans); font-size: .84rem; color: var(--tinta); margin: .5rem 0 0; }

/* A linha fina: não é contador, é um marco — «daqui para cima é novo». */
.novos-desde {
  display: flex; align-items: center; gap: .6rem; margin: .45rem 0;
  font-family: var(--sans); font-size: .74rem; font-weight: 500; color: var(--acento);
}
.novos-desde::before, .novos-desde::after { content: ""; flex: 1; border-top: 1px solid var(--acento); }

/* O `sticky` mora no LUGAR da barra, e não nela: um elemento pegajoso só
   anda dentro do próprio pai, e o pai da barra é o `.selecao-lugar`, da
   altura dela. Pregada na barra, ela ficava no fim da lista — a 2.000px da
   janela no Safari (L-310) —, e «Mandando 2 de 4» acontecia fora da vista.
   O pai do lugar é a coluna inteira, e é nela que ele anda. */
.selecao-lugar { position: sticky; bottom: calc(var(--barra-h) + .75rem); z-index: 5; }
.barra-selecao {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: .5rem;
  margin-top: .8rem; padding: .5rem; box-sizing: border-box;
  background: var(--papel-elev); border: 1px solid var(--papel-borda); border-radius: var(--raio);
  box-shadow: var(--sombra-erguida);
}
.progresso-envio {
  margin: 0 auto 0 .4rem; font-family: var(--sans); font-size: .9rem; font-weight: 600;
  font-variant-numeric: tabular-nums; color: var(--tinta);
}
.resultado-envio {
  font-family: var(--sans); font-size: .9rem; line-height: 1.5; color: var(--tinta);
  background: var(--papel-elev); border-left: 3px solid var(--acento);
  border-radius: 0 var(--raio-p) var(--raio-p) 0; padding: .6rem .9rem; margin: 0 0 1rem;
}
.resultado-envio p { margin: 0 0 .3rem; }
.resultado-envio ul { margin: 0 0 .5rem; padding-left: 1.1rem; }
.feed-vazio a { color: var(--acento); }

/* ── O Boletim ───────────────────────────────────────────────────────────── */
/* A edição é uma FOLHA, a mesma do artigo (`.artigo`): `--papel` pousado na
   mesa, a coluna em `--measure` e o corpo na tipografia de leitura do dono
   (`--corpo`, `--size`, `--leading`), porque a edição se lê, não se opera.
   A primeira versão pôs só o destaque num cartão e deixou os blocos direto
   na mesa; a segunda deu um cartão a cada bloco — e o dono respondeu que
   continuava chapado: rótulos em sans a 12px, MENORES que o texto que
   rotulavam, e tudo no mesmo peso. Aqui a hierarquia é de jornal, feita só
   com tamanho, peso e régua:
     · a manchete da edição a 2em, e um fio cheio embaixo do cabeçalho;
     · o destaque com título a 1.55em e as partes em cabeça corrida —
       «O que é.» em itálico, no corpo do texto e na cor do acento;
     · o bloco abre com fio cheio e o nome em serifa, maior que o título
       dos itens que ele contém;
     · o pé do item é uma linha só, em sans miúda — serviço, não notícia.
   O arquivo do mês fica fora da folha, na mesa: é navegação. */
.boletim-tela { max-width: calc(var(--measure) + var(--respiro) * 2); margin: 0 auto; }
.boletim-tela > :not(.boletim) { max-width: var(--measure); margin-left: auto; margin-right: auto; }
.boletim {
  padding: 2.4rem var(--respiro) 2rem; margin: .4rem 0 0;
  background: var(--papel); border-radius: var(--raio); box-shadow: var(--sombra-pousada);
  font-family: var(--corpo); font-size: var(--size); line-height: var(--leading); color: var(--tinta);
  --regra-mesa: color-mix(in srgb, var(--tinta) 13%, transparent);
}
/* O mesmo problema da `.artigo` no escuro: papel e mesa a 1,004:1. */
[data-tema="escuro"] .boletim { border: 1px solid var(--papel-borda); }
@media (max-width: 900px) {
  .boletim { border-radius: 0; padding-left: max(1.1rem, env(safe-area-inset-left)); padding-right: 1.1rem; }
}

.cabeca-edicao { margin: 0 0 2rem; padding: 0 0 1.1rem; border-bottom: 2px solid var(--tinta); }
.titulo-edicao {
  font-family: var(--corpo); font-size: 2em; line-height: 1.12; letter-spacing: -.015em;
  font-weight: 600; margin: 0 0 .45rem; text-wrap: balance;
}
.estado-edicao { font-family: var(--corpo); font-style: italic; font-size: .88em; line-height: 1.45; color: var(--tinta-2); margin: 0; }
.cabeca-edicao .ouvir-edicao { margin-top: .9rem; }
.escritores {
  display: inline-flex; flex-wrap: wrap; gap: 2px; padding: 3px; margin: 0 0 1.1rem;
  background: var(--papel-elev-2); border-radius: var(--raio-p); font-family: var(--sans);
}
.escritores a {
  min-height: var(--alvo); display: inline-flex; align-items: center; padding: 0 .9rem;
  border-radius: calc(var(--raio-p) - 2px); font-size: .86rem; font-weight: 500;
  color: var(--tinta-2); text-decoration: none;
}
.escritores a[aria-current] { background: var(--papel-elev); color: var(--tinta); font-weight: 600; box-shadow: var(--sombra-pousada); }

/* O número pendurado. A grade tem duas colunas — o `n` e o texto — e o
   cabeçalho do item se dissolve nela (`display: contents`): o número senta
   na linha de base do título, e tudo o que vem depois alinha pela segunda
   coluna. Com respiro que caiba (≥ 1100px), a coluna do número sai para a
   margem da folha e o texto dos itens alinha com a manchete. */
.destaque-edicao, .item-edicao {
  display: grid; grid-template-columns: 2.4rem minmax(0, 1fr); column-gap: .7rem; align-items: baseline;
}
.destaque-edicao > *, .item-edicao > * { grid-column: 2; }
.destaque-edicao > header, .item-edicao > header { display: contents; }
.destaque-edicao .n, .item-edicao .n {
  grid-column: 1; grid-row: 1; justify-self: end;
  font-family: var(--corpo); font-weight: 400; line-height: 1; color: var(--acento);
  font-variant-numeric: oldstyle-nums proportional-nums;
}
.destaque-edicao :is(h2, h3), .item-edicao :is(h2, h3) { grid-column: 2; grid-row: 1; margin: 0; }

.destaque-edicao { padding: 0 0 1.6rem; margin: 0 0 1.8rem; border-bottom: 1px solid var(--regra-mesa); }
.destaque-edicao .n { font-size: 2.1em; }
.destaque-edicao h2 {
  font-family: var(--corpo); font-size: 1.55em; line-height: 1.18; letter-spacing: -.01em;
  font-weight: 600; text-wrap: pretty;
}
.partes { margin: .7em 0 .5em; }
.partes > div { margin: 0 0 .85em; text-wrap: pretty; }
/* Cabeça corrida: o rótulo abre o parágrafo, no tamanho do texto. */
.partes dt { display: inline; font-style: italic; font-weight: 600; color: var(--acento); }
.partes dt::after { content: ".\2002"; }
.partes dd { display: inline; margin: 0; }
.boletim :is(.partes dd, .texto) a { color: var(--acento); text-underline-offset: 3px; }
.boletim :is(.partes dd, .texto) code { font-family: var(--mono); font-size: .88em; }

.bloco-edicao { margin: 2.6rem 0 0; }
.destaques-edicao + .bloco-edicao { margin-top: 2.2rem; }
.bloco-edicao > h2 {
  font-family: var(--corpo); font-size: 1.3em; line-height: 1.2; font-weight: 600; color: var(--tinta);
  margin: 0; padding: .55rem 0 0; border-top: 2px solid var(--tinta);
}
.itens-edicao { list-style: none; margin: 0; padding: 0; }
.item-edicao { padding: 1.1rem 0 .9rem; border-bottom: 1px solid var(--regra-mesa); }
.item-edicao:last-child { border-bottom: 0; padding-bottom: 0; }
.item-edicao .n { font-size: 1.4em; }
.item-edicao h3 { font-family: var(--corpo); font-size: 1.2em; line-height: 1.26; font-weight: 600; text-wrap: pretty; }
.item-edicao .texto { font-size: .95em; line-height: var(--leading); margin: .35em 0 .3em; text-wrap: pretty; }
/* Depois das regras de `margin` do destaque e do item: `@media` não empresta
   peso, e escrita antes ela era zerada por elas. */
@media (min-width: 1100px) {
  .destaque-edicao, .item-edicao { margin-left: -3.1rem; }
}
/* No telefone a coluna do número encolhe: 2,4rem de 390px é texto perdido. */
@media (max-width: 600px) {
  .destaque-edicao, .item-edicao { grid-template-columns: 1.5rem minmax(0, 1fr); column-gap: .45rem; }
  .destaque-edicao .n { font-size: 1.7em; }
  .titulo-edicao { font-size: 1.65em; }
}

/* O pé: de onde veio, o fio e os gestos, numa linha que quebra se precisar.
   Os alvos continuam com `--alvo` de altura; o que saiu foi a moldura. */
.pe-item {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0 .9rem;
  font-family: var(--sans); font-size: .78rem; line-height: 1.3; color: var(--tinta-2);
}
.fontes-edicao { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0 .9rem; }
.fontes-edicao li { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 0 .5rem; }
/* O nome da fonte é link e é alvo: com 44 de altura ele fica na mesma linha
   de base do «Mandar para…» ao lado, e o «AP» de duas letras deixa de ser
   um alvo de 17px (medido no Safari, L-310). */
.fontes-edicao .fonte-nome {
  min-height: var(--alvo); min-width: var(--alvo); box-sizing: border-box;
  display: inline-flex; align-items: center; color: var(--tinta-2); font-weight: 500;
  text-decoration-color: color-mix(in srgb, currentColor 40%, transparent); text-underline-offset: 3px;
}
.fontes-edicao .fonte-nome:hover { color: var(--tinta); }
.enviar-fonte {
  min-height: var(--alvo); padding: 0 .25rem; background: none; border: 0; cursor: pointer;
  font-family: var(--sans); font-size: .78rem; font-weight: 600; color: var(--acento);
}
.enviar-fonte:hover { text-decoration: underline; text-underline-offset: 3px; }
.fio {
  min-height: var(--alvo); display: inline-flex; align-items: center; padding: 0 .3rem; cursor: pointer;
  background: none; border: 0; font-family: var(--sans); font-size: .78rem; font-style: italic; color: var(--tinta-2);
}
.fio:hover, .fio[aria-expanded="true"] { color: var(--acento); }
.edicoes-do-fio ul { margin: 0 0 .4rem; padding-left: 1.1rem; font-family: var(--sans); font-size: .86rem; line-height: 1.5; }
.edicoes-do-fio a { display: inline-block; padding: .35rem 0; color: var(--tinta); }

.gestos { display: flex; flex-wrap: wrap; gap: .15rem; margin: 0 0 0 auto; }
.gesto {
  min-height: var(--alvo); padding: 0 .6rem; cursor: pointer; background: transparent;
  border: 0; border-radius: 999px;
  font-family: var(--sans); font-size: .76rem; font-weight: 500; color: var(--tenue);
}
.gesto:hover { color: var(--acento); }
.gesto[aria-pressed="true"] { background: var(--tinta); color: var(--papel); }
.rodape-edicao {
  font-family: var(--sans); font-size: .78rem; line-height: 1.5; color: var(--tenue);
  margin: 2rem 0 0; padding: .9rem 0 0; border-top: 1px solid var(--regra-mesa);
}
.boletim-vazio { padding: 2rem 0 1rem; font-family: var(--sans); font-size: .95rem; line-height: 1.6; color: var(--tinta-2); }
.boletim-vazio a { color: var(--acento); }

.arquivo { margin: 2.8rem 0 1rem; padding-top: 1.2rem; border-top: 1px solid var(--regra-mesa); }
.arquivo h2 { font-family: var(--serif); font-size: 1.12rem; font-weight: 600; margin: 0; }
.arquivo-nav { display: flex; justify-content: space-between; gap: 1rem; margin: .2rem 0 .5rem; }
.arquivo-nav a {
  min-height: var(--alvo); display: inline-flex; align-items: center;
  font-family: var(--sans); font-size: .86rem; color: var(--tinta-2);
}
.busca-arquivo { margin: 0 0 .5rem; }
.arquivo-edicoes { list-style: none; margin: 0; padding: 0; font-family: var(--sans); }
.arquivo-edicoes li { border-bottom: 1px solid var(--regra-mesa); }
.arquivo-edicoes a, .arquivo-edicoes .nao-saiu {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .1rem .7rem;
  min-height: var(--alvo); box-sizing: border-box; padding: .6rem 0; text-decoration: none; color: var(--tinta);
}
.arquivo-edicoes .data { flex: none; min-width: 7.5rem; font-size: .8rem; font-weight: 600; color: var(--tinta-2); }
.arquivo-edicoes .titulo { font-family: var(--serif); font-size: .98rem; }
/* «do motor» vai DEPOIS do título: antes dele, os títulos das edições do
   motor começavam mais à direita que os da skill, e a coluna de títulos do
   arquivo saía serrilhada (Safari, L-310). */
.arquivo-edicoes .escritor { order: 1; font-size: .74rem; color: var(--tenue); }
.arquivo-edicoes .nao-saiu { font-size: .86rem; color: var(--tinta-2); }

/* ── As Fontes ───────────────────────────────────────────────────────────── */
.fontes-tela, .ajustes-tela { max-width: var(--measure); margin: 0 auto; }
.adicionar-fonte, .nova-secao {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .5rem; align-items: end; margin: 0 0 1rem;
}
.adicionar-fonte .erro-lugar, .nova-secao .erro-lugar { grid-column: 1 / -1; }
.nova-secao { margin-top: 1.6rem; }
.previa-fonte {
  display: grid; gap: .6rem; padding: 1rem; margin: 0 0 1.4rem;
  background: var(--papel-elev); border: 1px solid var(--papel-borda); border-radius: var(--raio);
  box-shadow: var(--sombra-pousada);
}
.previa-endereco { margin: 0; font-family: var(--mono); font-size: .8rem; color: var(--tinta-2); overflow-wrap: anywhere; }
.previa-fonte .sub { margin: 0; }
.itens-previa { margin: 0; padding-left: 1.3rem; font-family: var(--serif); font-size: .95rem; line-height: 1.45; }
.itens-previa .data { font-family: var(--sans); font-size: .76rem; color: var(--tenue); }

.secao-fontes { margin: 1.5rem 0 0; }
.secao-fontes > header {
  display: flex; align-items: center; flex-wrap: wrap; gap: .4rem .6rem;
  padding-bottom: .3rem; border-bottom: 1px solid var(--regra-mesa);
}
.secao-fontes > header h2 { flex: 1 1 10rem; margin: 0; font-family: var(--serif); font-size: 1.08rem; font-weight: 600; }
.secao-acoes, .fonte-acoes { display: inline-flex; gap: .35rem; }
.secao-acoes .btn, .fonte-acoes .btn {
  background: transparent; color: var(--tinta); border: 1px solid var(--borda-controle); box-shadow: none;
}
.lista-fontes-secao { list-style: none; margin: 0; padding: 0; }
.fonte { padding: .55rem 0; border-bottom: 1px solid var(--regra-mesa); }
/* Uma grade, e não um flex que quebra: com flex, a fonte de nome curto e
   saúde curta («NIST · viva») cabia numa linha e a de saúde longa («morta:
   404») jogava os botões para a linha de baixo — no iPhone, cada fonte saía
   com um desenho (Safari, L-310). Aqui os botões têm sempre a mesma coluna à
   direita, e a saúde desce para baixo do nome abaixo de 40rem. */
.fonte-linha {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: .1rem .7rem;
}
.fonte-linha .fonte-nome { grid-column: 1; font-family: var(--serif); font-size: .98rem; font-weight: 600; overflow-wrap: anywhere; }
.fonte-linha .saude { grid-column: 1; grid-row: 2; }
.fonte-linha .fonte-acoes { grid-column: 2; grid-row: 1 / span 2; }
@media (min-width: 40rem) {
  .fonte-linha { grid-template-columns: minmax(0, 1fr) auto auto; }
  .fonte-linha .saude { grid-column: 2; grid-row: 1; }
  .fonte-linha .fonte-acoes { grid-column: 3; grid-row: 1; }
}
.fonte-site { margin: .1rem 0 0; font-family: var(--sans); font-size: .76rem; color: var(--tenue); overflow-wrap: anywhere; }

/* A saúde é dita em palavras; o ponto só a acompanha — nunca só cor. Viva é
   o ponto cheio, quieta é o ponto cheio em tom tênue (está bem, só publica
   pouco: nada de perigo, que 41 de 102 em vermelho ensinavam a não olhar),
   vazia é o aro, morta vem na cor de perigo, e a que ainda não foi lida é o
   aro fino e tênue. (Era tracejado: num círculo de 8px o
   tracejado do Safari vira dois riscos soltos, e a captura da L-310 mostrou
   um glifo quebrado, e não um aro.) */
.saude {
  display: inline-flex; align-items: center; gap: .35rem;
  font-family: var(--sans); font-size: .76rem; font-weight: 500; color: var(--tinta-2);
}
.saude::before {
  content: ""; width: .5rem; height: .5rem; border-radius: 50%; box-sizing: border-box;
  background: var(--tinta-2); border: 1.5px solid var(--tinta-2);
}
.saude[data-estado="quieto"]::before { background: var(--tenue); border-color: var(--tenue); }
.saude[data-estado="vazio"]::before { background: transparent; }
.saude[data-estado="nova"]::before { background: transparent; border-width: 1px; border-color: var(--tenue); }
.saude[data-estado="morto"] { color: var(--perigo); }
.saude[data-estado="morto"]::before { background: var(--perigo); border-color: var(--perigo); }

:is(.editar-fonte, .renomear-secao, .apagar-secao) {
  display: grid; gap: .6rem; padding: .8rem; margin: .5rem 0;
  background: var(--papel-elev-2); border-radius: var(--raio-p);
}
.apagar-secao p { margin: 0; font-family: var(--sans); font-size: .9rem; }

.opml { margin: 2.2rem 0 1rem; padding-top: 1rem; border-top: 1px solid var(--regra-mesa); }
.opml h2 { font-family: var(--serif); font-size: 1.08rem; font-weight: 600; margin: 0 0 .3rem; }
.importar-opml { cursor: pointer; }
.importar-opml:focus-within { outline: 2px solid var(--foco); outline-offset: 2px; }
.resultado-opml { font-family: var(--sans); font-size: .88rem; line-height: 1.5; margin-top: .7rem; }
.resultado-opml p { margin: 0 0 .3rem; }
.resultado-opml ul { margin: 0; padding-left: 1.1rem; }

/* ── Os Ajustes ──────────────────────────────────────────────────────────── */
.ajustes-gazeta { display: grid; gap: 1.4rem; }
.ajustes-gazeta .campo { border: 0; margin: 0; padding: 0; min-width: 0; display: grid; gap: .45rem; }
.ajustes-gazeta legend { padding: 0; margin: 0 0 .3rem; font-family: var(--serif); font-size: 1.05rem; font-weight: 600; }
.ajustes-gazeta .sub { margin: 0; line-height: 1.45; }
.frequencia-atual {
  margin: 0; font-family: var(--sans); font-size: .86rem; color: var(--tinta-2);
  border-left: 3px solid var(--acento); padding: .35rem .7rem;
}
.conta-criterio { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
.erro-campo { margin: 0; font-family: var(--sans); font-size: .84rem; font-weight: 600; color: var(--perigo); }
.erro-campo:empty { display: none; }

.blocos-ajuste, .partes-ajuste { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.bloco-ajuste {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .5rem; align-items: end; padding: .7rem;
  background: var(--papel-elev); border: 1px solid var(--papel-borda); border-radius: var(--raio-p);
}
.bloco-campos { display: grid; gap: .45rem; }
.bloco-botoes { display: flex; gap: .3rem; }
.bloco-botoes .btn { min-width: var(--alvo); }
.partes-ajuste li { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .5rem; align-items: center; }
@media (max-width: 40rem) { .bloco-ajuste { grid-template-columns: minmax(0, 1fr); } }
.ajustes-gazeta [data-mais-bloco], .ajustes-gazeta [data-mais-parte] { justify-self: start; }

.segmentado-ajuste {
  display: inline-flex; flex-wrap: wrap; gap: 2px; padding: 3px; justify-self: start;
  background: var(--papel-elev-2); border-radius: var(--raio-p);
}
.opcao-radio { position: relative; display: inline-flex; }
.opcao-radio input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.segmentado-ajuste .opcao-radio span {
  min-height: var(--alvo); min-width: var(--alvo); box-sizing: border-box; padding: 0 .9rem;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: calc(var(--raio-p) - 2px); font-family: var(--sans); font-size: .86rem; font-weight: 500; color: var(--tinta-2);
}
.segmentado-ajuste .opcao-radio input:checked + span {
  background: var(--papel-elev); color: var(--tinta); font-weight: 600; box-shadow: var(--sombra-pousada);
}
.opcao-radio input:focus-visible + span { outline: 2px solid var(--foco); outline-offset: 1px; }

.freq-campos { display: flex; flex-wrap: wrap; gap: .6rem 1rem; align-items: end; }
.freq-campos label { display: grid; gap: .25rem; min-width: 8rem; flex: 1 1 8rem; }
.frequencia[data-tipo="diaria"] [data-para],
.frequencia[data-tipo="semanal"] [data-para="cada"],
.frequencia[data-tipo="cada"] [data-para="semanal"] { display: none; }

.escritores-ajuste { display: grid; gap: .4rem; }
.escritores-ajuste .opcao-radio { display: block; }
.escritores-ajuste .opcao-radio span {
  display: block; min-height: var(--alvo); box-sizing: border-box; padding: .6rem .8rem;
  border: 1px solid var(--borda-controle); border-radius: var(--raio-p);
  font-family: var(--sans); font-size: .88rem; line-height: 1.4; color: var(--tinta-2);
}
.escritores-ajuste .opcao-radio strong { color: var(--tinta); font-weight: 600; }
.escritores-ajuste .opcao-radio input:checked + span {
  border-color: var(--acento); background: color-mix(in srgb, var(--acento) 8%, var(--papel-elev));
}

.salvar-ajustes { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; }
.estado-ajustes { margin: 0; font-family: var(--sans); font-size: .88rem; color: var(--tinta-2); }
.outras-gazetas { margin: 2rem 0 0; }
.zona-apagar {
  margin: 2.4rem 0 1rem; padding: 1rem; border-radius: var(--raio);
  border: 1px solid color-mix(in srgb, var(--perigo) 45%, transparent);
}
.zona-apagar h2 { font-family: var(--serif); font-size: 1.02rem; font-weight: 600; margin: 0 0 .3rem; }
.zona-apagar .sub { margin: 0 0 .7rem; }
.noticias .btn.perigo { background: transparent; color: var(--perigo); border-color: currentColor; box-shadow: none; }

/* ── Listas de Leitura (spec 61) ── */
/* ═══════════════════════════════════════════════════════════════════════════
   A lista é uma fila, na ordem — e a tela diz isso: número à esquerda, o
   título, e os gestos à direita. Só tokens do núcleo, e os três temas saem
   deles (claro, escuro, auto). Todo controle isolado tem 44px (`--alvo`);
   os círculos das fileiras de ação seguem o registro de cada contexto. */

/* O gesto «Mandar para lista…» nas fileiras de ação: aceso quando o item JÁ
   está numa lista (o botão diz onde, no `title`). */
.redondo.acao-lista[aria-pressed="true"] {
  color: var(--acento); border-color: var(--acento);
  background: color-mix(in srgb, var(--acento) 12%, var(--papel-elev));
}

/* ── /listas ── */
.cabeca-listas {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; margin: 0 0 .8rem;
}
.cabeca-listas .titulo-tela { margin: 0; }
.cabeca-listas .btn, .tela-lista .btn, .mandar-para .btn { min-height: var(--alvo); padding: 0 .9rem; }
.nova-lista { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .5rem; margin: 0 0 .6rem; }
.nova-lista[hidden] { display: none; }
.nova-lista .campo { display: flex; flex-direction: column; gap: .25rem; flex: 1 1 14rem;
  font-family: var(--sans); font-size: .82rem; color: var(--tinta-2); }
.nova-lista input, .renomear input, .mover-posicao input {
  box-sizing: border-box; min-height: var(--alvo); padding: 0 .7rem;
  font: 400 1rem/1.2 var(--sans); color: var(--tinta);
  background: var(--papel); border: 1px solid var(--borda-controle); border-radius: var(--raio-p);
}
.nova-lista input:focus-visible, .renomear input:focus-visible, .mover-posicao input:focus-visible {
  outline: 2px solid var(--foco); outline-offset: 1px;
}
.cabeca-listas ~ .dica, .tela-lista .dica { font-family: var(--sans); font-size: .84rem; color: var(--tinta-2); margin: 0 0 .6rem; }
.cabeca-listas ~ .dica:empty { display: none; }

.cartoes-listas { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr)); }
/* A moldura é do <li>: dentro dela, o link (abre a lista) e o «Puxar» da vez,
   irmãos — botão dentro de link não é HTML válido (pedido do dono, 18/09). */
.cartao-lista {
  display: flex; flex-direction: column; box-sizing: border-box; height: 100%;
  background: var(--papel-elev); border: 1px solid var(--regra); border-radius: var(--raio);
}
.cartao-lista:has(> a:hover), .cartao-lista:has(> a:focus-visible) { border-color: var(--acento); }
.cartao-lista a {
  flex: 1; display: flex; align-items: center; gap: .9rem; min-height: var(--alvo);
  padding: .8rem 1rem; box-sizing: border-box; border-radius: var(--raio);
  color: var(--tinta); text-decoration: none;
}
.cartao-lista a:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }
.cartao-lista > .puxar { align-self: flex-start; min-height: var(--alvo); padding: 0 .9rem;
  margin: 0 1rem .8rem; white-space: nowrap; }
.capa-lista { flex: none; width: 3.2rem; container-type: inline-size; }
/* `.obra` só para a capa desenhada ter pele (L-323); o resto do `.obra` da
   estante (coluna flex de altura cheia) não vale aqui. */
.capa-lista.obra { display: block; height: auto; }
.capa-lista .capa { display: flex; width: 100%; aspect-ratio: 2 / 3; border-radius: 3px; overflow: hidden; }
.texto-lista { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.texto-lista .nome { font-family: var(--serif); font-size: 1.08rem; font-weight: 600; }
.texto-lista .proximo { font-family: var(--sans); font-size: .86rem; color: var(--tinta-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.texto-lista .conta { font-family: var(--sans); font-size: .78rem; color: var(--tenue); font-variant-numeric: tabular-nums; }

.aviso-offline, .progresso-lista {
  font-family: var(--sans); font-size: .86rem; color: var(--tinta);
  background: var(--papel-elev-2); border-left: 3px solid var(--tenue);
  border-radius: 0 var(--raio-p) var(--raio-p) 0; padding: .5rem .8rem; margin: 0 0 .8rem;
}
.progresso-lista { border-left-color: var(--acento); font-variant-numeric: tabular-nums; }

/* ── /listas/:id ── */
.cabeca-lista { display: flex; align-items: center; gap: .6rem; margin: 0 0 .2rem; flex-wrap: wrap; }
.cabeca-lista .titulo-tela { margin: 0; display: flex; align-items: center; gap: .5rem; flex: 1 1 auto; min-width: 0; }
.cabeca-lista .titulo-tela .ic { flex: none; width: 1.3rem; height: 1.3rem; color: var(--acento); }
.cabeca-lista .titulo-tela .ic svg { width: 100%; height: 100%; display: block; }
.renomear { display: flex; flex-wrap: wrap; gap: .5rem; flex: 1 1 16rem; }
.renomear input { flex: 1 1 12rem; font-family: var(--serif); font-size: 1.1rem; }
.menu-lista { position: relative; flex: none; }
.menu-lista > summary {
  list-style: none; display: grid; place-items: center; cursor: pointer;
  width: var(--alvo); height: var(--alvo); border-radius: 50%;
  font: 700 1.2rem/1 var(--sans); color: var(--tinta-2); border: 1px solid transparent;
}
.menu-lista > summary::-webkit-details-marker { display: none; }
.menu-lista > summary:hover, .menu-lista > summary:focus-visible { color: var(--acento); border-color: var(--regra); }
.menu-lista[open] > summary { color: var(--acento); border-color: var(--acento); }
.menu-itens {
  position: absolute; right: 0; top: calc(100% + .3rem); z-index: 20;
  display: flex; flex-direction: column; gap: .3rem; padding: .4rem; min-width: 11rem;
  background: var(--papel-elev); border: 1px solid var(--regra); border-radius: var(--raio);
  box-shadow: var(--sombra-erguida);
}
.menu-itens .btn { text-align: left; }
.tela-lista .btn.perigo, .apagar-lista .btn.perigo { color: var(--perigo); border-color: currentColor; background: transparent; }
.conta-lista { font-family: var(--sans); font-size: .82rem; color: var(--tinta-2); margin: 0 0 1rem; }

/* A fila mora direto na mesa (`--tela`), e `--regra` é fio de PAPEL: sobre
   a mesa do tema claro ele mediu 1,00 no Safari — a divisória não existia
   (L-323). A régua das Notícias: tinta a 14%, que acompanha os três temas. */
.tela-lista { --regra-mesa: color-mix(in srgb, var(--tinta) 14%, transparent); }
.itens-lista { list-style: none; margin: 0; padding: 0; counter-reset: none; }
.item-lista {
  display: grid; align-items: center; column-gap: .6rem;
  grid-template-columns: 2.2rem var(--alvo) minmax(0, 1fr) auto;
  padding: .45rem .2rem; border-bottom: 1px solid var(--regra-mesa);
}
.item-lista.pego { background: color-mix(in srgb, var(--acento) 10%, transparent); border-radius: var(--raio-p); }
.item-lista .posicao {
  font: 600 .95rem/1 var(--sans); color: var(--tenue); text-align: right;
  font-variant-numeric: tabular-nums;
}
.item-lista:first-child .posicao { color: var(--acento); }
/* No leito tingido da linha pega, `--tenue` cai a 4,03 (L-323). */
.item-lista.pego .posicao { color: var(--tinta-2); }
.marcar-item { display: grid; place-items: center; width: var(--alvo); height: var(--alvo); cursor: pointer; }
.marcar-item input { width: 1.15rem; height: 1.15rem; margin: 0; accent-color: var(--acento); cursor: pointer; }
.item-lista .alvo {
  display: flex; flex-direction: column; gap: .12rem; min-width: 0; min-height: var(--alvo);
  justify-content: center; color: var(--tinta); text-decoration: none;
}
.item-lista .alvo .titulo { font-family: var(--serif); font-size: 1rem; line-height: 1.3;
  overflow-wrap: anywhere; }
.item-lista .alvo .meta { font-family: var(--sans); font-size: .76rem; color: var(--tinta-2); }
.item-lista .alvo:hover .titulo, .item-lista .alvo:focus-visible .titulo { color: var(--acento); }
.item-lista .alvo:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; border-radius: var(--raio-p); }
/* Com algo pego, a linha inteira é o alvo do «pôr aqui». */
.tela-lista:has(.barra-mover) .item-lista:not(.pego) .alvo { cursor: copy; }
.acoes-item { display: flex; align-items: center; gap: .35rem; justify-content: flex-end; }
.acoes-item .redondo { width: var(--alvo); height: var(--alvo); min-height: var(--alvo); font-size: 1rem; }
.acoes-item .pegar[aria-pressed="true"] {
  color: var(--sobre-acento); background: var(--acento); border-color: var(--acento);
}
.acoes-item .puxar { min-height: var(--alvo); padding: 0 .9rem; white-space: nowrap; }
.mais-lista { text-align: center; margin: 1rem 0; }

/* A barra do pé: «Movendo 3 itens · Topo · Fim · Posição · Mandar… · Cancelar».
   Presa ACIMA da barra de navegação do telefone, no fluxo da coluna — a mesma
   lição do `.selecao-lugar` das Notícias: pegajosa no pé da tela visível. */
.barra-mover {
  position: sticky; bottom: calc(var(--barra-h) + .75rem); z-index: 6;
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
  margin-top: 1rem; padding: .5rem; box-sizing: border-box;
  background: var(--papel-elev); border: 1px solid var(--regra); border-radius: var(--raio);
  box-shadow: var(--sombra-erguida); font-family: var(--sans);
}
.barra-mover .movendo { font-weight: 600; font-size: .9rem; color: var(--tinta); margin-right: auto;
  padding-left: .3rem; font-variant-numeric: tabular-nums; }
.mover-posicao { display: flex; align-items: center; gap: .3rem; }
.mover-posicao label { display: flex; align-items: center; gap: .35rem; font-size: .84rem; color: var(--tinta-2); }
.mover-posicao input { width: 4.2rem; text-align: center; font-variant-numeric: tabular-nums; }
/* «Ir» é uma palavra de duas letras: sem piso, o alvo media 39 px (L-323). */
.barra-mover .btn { min-width: var(--alvo); }

/* No telefone, o título da linha ganha a largura: a caixa e o número ficam,
   e os gestos descem para baixo do título. */
@media (max-width: 40rem) {
  .item-lista { grid-template-columns: 1.8rem var(--alvo) minmax(0, 1fr); row-gap: .2rem; }
  .acoes-item { grid-column: 3; justify-content: flex-start; flex-wrap: wrap; }
  .barra-mover .movendo { flex-basis: 100%; }
}

/* ── A folha «Mandar para lista…» ── */
.mandar-para .titulo { font-family: var(--serif); font-size: 1.1rem; font-weight: 600; margin: 0 0 .3rem; }
.mandar-para .alvo { font-family: var(--serif); color: var(--tinta-2); margin: 0 0 .8rem; }
.mandar-para .aviso-estudo {
  font-size: .86rem; line-height: 1.45; color: var(--tinta); margin: 0 0 .8rem;
  background: color-mix(in srgb, var(--perigo) 8%, var(--papel-elev));
  border-left: 3px solid var(--perigo); border-radius: 0 var(--raio-p) var(--raio-p) 0; padding: .5rem .7rem;
}
.mandar-para .destinos { list-style: none; margin: 0 0 .6rem; padding: 0; overflow-y: auto; min-height: 0;
  display: flex; flex-direction: column; gap: .3rem; }
.mandar-para .destino {
  display: flex; align-items: center; justify-content: space-between; gap: .8rem; width: 100%;
  min-height: var(--alvo); padding: .4rem .8rem; box-sizing: border-box; text-align: left; cursor: pointer;
  font: 500 .95rem/1.3 var(--sans); color: var(--tinta);
  background: var(--papel); border: 1px solid var(--regra); border-radius: var(--raio-p);
}
.mandar-para .destino .conta { font-size: .8rem; color: var(--tinta-2); font-variant-numeric: tabular-nums; flex: none; }
.mandar-para .destino:hover:not([disabled]), .mandar-para .destino:focus-visible { border-color: var(--acento); }
.mandar-para .destino:focus-visible { outline: 2px solid var(--foco); outline-offset: 1px; }
.mandar-para .destino[aria-pressed="true"] {
  border-color: var(--acento); background: color-mix(in srgb, var(--acento) 12%, var(--papel));
}
.mandar-para .destino[disabled] { opacity: .6; cursor: default; }
.mandar-para .destino.nova { color: var(--acento); justify-content: flex-start; }
.mandar-para .vazio-destinos { font-size: .86rem; color: var(--tinta-2); padding: .3rem .2rem; }
.mandar-para .nova-lista { margin: 0 0 .5rem; }
.mandar-para .dica { font-size: .86rem; color: var(--tinta-2); min-height: 1.2em; margin: 0 0 .6rem; }
.mandar-para .botoes { display: flex; justify-content: flex-end; gap: .5rem; margin: 0; }

/* ── O diálogo do apagar com itens ── */
.destinos-itens { display: flex; flex-direction: column; gap: .5rem; margin: 0 0 1rem; }
.destinos-itens .btn {
  display: flex; flex-direction: column; align-items: flex-start; gap: .15rem; text-align: left;
  min-height: var(--alvo); padding: .55rem .9rem; font-size: .95rem; font-weight: 600;
}
.destinos-itens .btn small { font-weight: 400; font-size: .8rem; color: var(--tinta-2); }
/* O `.btn` é cromo escuro: `--tinta-2` por cima mediu 2,04 (L-323). A linha
   de baixo segue a tinta do botão, um degrau mais fraca. */
.destinos-itens .btn:not(.perigo) small { color: color-mix(in srgb, currentColor 80%, transparent); }

/* ── A barra do telefone: só o ícone  (L-323) ──
   Com o sexto destino cada coluna do iPhone ficou com 55 px, e «Listas de
   Leitura» quebrou em duas linhas no Safari (390 px): a barra cresceu de 62
   para 83 px e passou por cima da barra de mover. Como o plano decidiu para
   esse caso, no telefone a barra é só de ícones; o rótulo continua no DOM,
   fora da vista, e é ele o nome do destino para o VoiceOver. O iPad e a
   lateral do Mac têm largura, e mantêm a palavra. */
@media (max-width: 40rem) {
  #barra-nav .nav-rotulo {
    position: absolute; width: 1px; height: 1px; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  #barra-nav a { justify-content: center; }
  #barra-nav a .ic, #barra-nav a .ic svg { width: 24px; height: 24px; }
}

/* A nota do «mandado» (fica até o Fechar, como a nota de falha). */
.desfazer.aviso-mandado { background: var(--tinta); color: var(--papel); }

/* ── A faixa dos envios  (spec 68 §15) ────────────────────────────────────────
   O estado do que subiu para converter, em qualquer tela: presa ao pé, ACIMA da
   barra de navegação do telefone (a mesma lição da `.barra-mover`), estreita no
   computador para não cobrir a coluna de leitura. Some quando não há o que dizer. */
#envios {
  position: fixed; z-index: 40;
  right: max(.75rem, env(safe-area-inset-right)); bottom: calc(var(--barra-h, 0px) + .75rem);
  width: min(24rem, calc(100vw - 1.5rem)); box-sizing: border-box;
  display: flex; flex-direction: column; gap: .35rem;
  font-family: var(--sans); font-size: .84rem; line-height: 1.35;
}
#envios[hidden] { display: none; }
#envios .envio {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; column-gap: .4rem;
  padding: .5rem .55rem .5rem .75rem; border-radius: var(--raio);
  background: var(--papel-elev); color: var(--tinta); border: 1px solid var(--regra);
  box-shadow: var(--sombra-erguida);
}
#envios .envio-texto { overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
#envios .envio-andamento { color: var(--tinta-2); }
#envios .envio-falhou { border-color: color-mix(in srgb, var(--perigo) 55%, var(--regra)); }
#envios .envio-pronto { border-color: color-mix(in srgb, var(--acento) 55%, var(--regra)); }
#envios .envio-abrir { color: var(--acento); font-weight: 600; text-decoration: none;
  min-height: var(--alvo); display: inline-flex; align-items: center; padding: 0 .35rem; }
#envios .envio-dispensar { min-width: var(--alvo); min-height: var(--alvo); border: 0; background: none;
  color: var(--tinta-2); font-size: 1.15rem; line-height: 1; cursor: pointer; border-radius: var(--raio); }
#envios .envio-dispensar:hover { color: var(--tinta); }
#envios details { grid-column: 1 / -1; color: var(--tinta-2); font-size: .78rem; }
#envios details summary { cursor: pointer; min-height: 1.6rem; }
#envios details p { margin: .15rem 0 .1rem; overflow-wrap: anywhere; }
#envios .envio-mais { margin: 0; text-align: right; color: var(--tinta-2); font-size: .78rem; }
/* A pergunta do quality check (spec 68 §17): a linha que espera resposta. O
   texto ocupa a largura toda e os dois botões vão embaixo, o que continua à
   direita — o polegar acha «Converter» onde acha o «Abrir» das outras linhas. */
#envios .envio-confirmar { border-color: color-mix(in srgb, var(--acento) 75%, var(--regra)); }
#envios .envio-confirmar .envio-texto { grid-column: 1 / -1; }
#envios .envio-decisao { grid-column: 1 / -1; display: flex; justify-content: flex-end; flex-wrap: wrap; gap: .4rem; margin-top: .45rem; }
#envios .envio-decisao .btn { min-height: var(--alvo); }
