@aurea-uds/core 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/aurea.css +253 -17
  2. package/package.json +1 -1
package/dist/aurea.css CHANGED
@@ -286,6 +286,20 @@ button,a,[role="button"],input,textarea,select { outline:none; }
286
286
  :focus-visible { outline:2px solid var(--focus-strong); outline-offset:2px; box-shadow:none; border-color:var(--focus-strong)!important; }
287
287
  button { color:inherit; }
288
288
  a { color:var(--primary); text-underline-offset:3px; }
289
+ /* LINK DE TEXTO NO TEMA CLARO — reprovação de WCAG AA que estava latente desde sempre, e que só
290
+ apareceu quando o catálogo ganhou a primeira página com link em corpo de texto (a do `Prose`,
291
+ item L5). Medido em 15/08/2026 na página gerada: o amarelo puro sobre a superfície clara dá
292
+ **1,68:1**, contra os 4,5:1 do AA. Com a correção, **6,92:1**.
293
+ NÃO é decisão de aparência nova, e é por isso que entra sem interromper o lote: a fórmula, o
294
+ guarda de tema e a razão já estão neste arquivo, escritos para o `.btn-link-primary` (linha
295
+ ~247) e para a linguagem de selecionado — "no tema claro o amarelo puro como texto dá 1.6:1,
296
+ longe dos 4.5:1 do AA, então o rótulo aprofunda com --foreground e segue âmbar". O bare `<a>`
297
+ simplesmente nunca tinha recebido o mesmo tratamento.
298
+ `:not([class])` é a parte cirúrgica, e não zelo: sem ele esta regra (0,2,1) passaria por cima
299
+ de `.btn` (0,1,0), de `.doc-nav a` e de `.toc a`, trocando a cor de componentes que já resolvem
300
+ a própria. Assim ela alcança exatamente o que está quebrado — o link que o conteúdo escreve —
301
+ e nenhum outro. Limite declarado: link de conteúdo que carregue classe própria é do consumidor. */
302
+ [data-theme="light"] a:not([class]) { color:color-mix(in oklab, var(--primary) 45%, var(--foreground)); }
289
303
  img,svg { display:block; }
290
304
  /* O `display:none` que o browser dá pro atributo `hidden` vem da folha do UA e PERDE de
291
305
  qualquer `display:` de classe nossa — o painel some do fluxo de acessibilidade mas
@@ -475,8 +489,14 @@ img,svg { display:block; }
475
489
  /* 04. COMPONENTES PRIMITIVOS */
476
490
  /* ========================================================================== */
477
491
  .btn { --btn-bg:transparent; --btn-fg:var(--foreground); --btn-border:transparent; display:inline-flex; align-items:center; justify-content:center; gap:8px; height:var(--control-h-md); padding:0 15px; border:1px solid var(--btn-border); border-radius:var(--radius-control); background:var(--btn-bg); color:var(--btn-fg); font-size:var(--text-sm); font-weight:var(--weight-medium); line-height:var(--leading-none); text-decoration:none; white-space:nowrap; cursor:pointer; transition:transform var(--duration-fast) var(--ease-standard),background var(--duration-fast),border-color var(--duration-fast),color var(--duration-fast),opacity var(--duration-fast); }
478
- .btn:hover:not(:disabled) { transform:none; } .btn:active:not(:disabled) { transform:scale(.97); opacity:.9; }
479
- .btn:disabled { opacity:.45; cursor:not-allowed; }
492
+ .btn:hover:not(:disabled):not([aria-disabled="true"]) { transform:none; } .btn:active:not(:disabled) { transform:scale(.97); opacity:.9; }
493
+ /* Duas formas de "não dá para fazer isto", e a diferença é QUEM alcança a explicação.
494
+ `:disabled` tira o controle da ordem de foco — medido em 13/08/2026: quem usa teclado nunca
495
+ chega nele, então uma dica pendurada ali não é lida por ninguém. O embrulho de <span> que a
496
+ referência do MUI documenta resolve o ponteiro e NÃO resolve o teclado (o span nasce com
497
+ tabIndex -1, medido). `[aria-disabled="true"]` mantém o controle focável e inerte — é ele
498
+ que se usa quando existe um PORQUÊ a dizer. A pele é a mesma; o que muda é o alcance. */
499
+ .btn:disabled,.btn[aria-disabled="true"] { opacity:.45; cursor:not-allowed; }
480
500
  /* Cinco alturas, todas de token de densidade (autorizado pelo Victor em 24/07/2026). O raio
481
501
  é pill em TODAS — o tamanho muda altura e respiro, nunca a forma. Em ponteiro grosso o
482
502
  mínimo de 44px lá embaixo pega o xs e o sm, então alvo pequeno não vira alvo impossível. */
@@ -487,22 +507,22 @@ img,svg { display:block; }
487
507
  /* Largura total: para rodapé de formulário e tela estreita. Só a largura muda. */
488
508
  .btn-block { width:100%; }
489
509
  .btn-primary { --btn-bg:var(--primary); --btn-fg:var(--primary-foreground); --btn-border:transparent; }
490
- .btn-primary:hover:not(:disabled) { --btn-bg:var(--primary-hover); --btn-border:transparent; }
510
+ .btn-primary:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:var(--primary-hover); --btn-border:transparent; }
491
511
  .btn-secondary { --btn-bg:var(--secondary); --btn-fg:var(--secondary-foreground); --btn-border:transparent; }
492
- .btn-secondary:hover:not(:disabled) { --btn-bg:var(--secondary-hover); --btn-border:transparent; }
512
+ .btn-secondary:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:var(--secondary-hover); --btn-border:transparent; }
493
513
  .btn-outline { --btn-bg:transparent; --btn-fg:var(--foreground); --btn-border:var(--border-strong); }
494
- .btn-outline:hover:not(:disabled) { --btn-bg:var(--accent); }
514
+ .btn-outline:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:var(--accent); }
495
515
  .btn-ghost { --btn-bg:transparent; --btn-fg:var(--foreground); --btn-border:transparent; }
496
- .btn-ghost:hover:not(:disabled) { --btn-bg:var(--accent); --btn-fg:var(--accent-foreground); }
516
+ .btn-ghost:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:var(--accent); --btn-fg:var(--accent-foreground); }
497
517
  .btn-danger { --btn-bg:var(--destructive); --btn-fg:var(--destructive-foreground); --btn-border:transparent; }
498
- .btn-danger:hover:not(:disabled) { --btn-bg:var(--danger-400); }
518
+ .btn-danger:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:var(--danger-400); }
499
519
  /* Destrutivo em OUTRAS hierarquias: apagar não é sempre a ação principal da tela. O tom é o
500
520
  mesmo (--destructive); o que muda é o peso. No claro o vermelho puro como texto não chega
501
521
  a 4.5:1, então aprofunda com --foreground — mesmo tratamento do amarelo. */
502
522
  .btn-danger-outline { --btn-bg:transparent; --btn-fg:var(--destructive); --btn-border:var(--destructive); }
503
- .btn-danger-outline:hover:not(:disabled) { --btn-bg:color-mix(in oklab, var(--destructive) 14%, transparent); }
523
+ .btn-danger-outline:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:color-mix(in oklab, var(--destructive) 14%, transparent); }
504
524
  .btn-danger-ghost { --btn-bg:transparent; --btn-fg:var(--destructive); --btn-border:transparent; }
505
- .btn-danger-ghost:hover:not(:disabled) { --btn-bg:color-mix(in oklab, var(--destructive) 14%, transparent); }
525
+ .btn-danger-ghost:hover:not(:disabled):not([aria-disabled="true"]) { --btn-bg:color-mix(in oklab, var(--destructive) 14%, transparent); }
506
526
  [data-theme="light"] .btn-danger-outline,[data-theme="light"] .btn-danger-ghost,[data-theme="light"] .btn-link-danger { --btn-fg:color-mix(in oklab, var(--destructive) 62%, var(--foreground)); }
507
527
  /* LINK: aparência de texto, sem cápsula e sem altura de controle — o sublinhado é o que diz
508
528
  que é clicável, então ele existe desde o repouso (revelar no hover esconde a affordance).
@@ -511,7 +531,7 @@ img,svg { display:block; }
511
531
  medido no catálogo, o "Learn more" é ação isolada dentro de um flex, não link no meio de
512
532
  prosa, e media 67×13px. O texto continua onde está — a caixa cresce centrada nele. */
513
533
  .btn-link { height:auto; min-height:24px; padding:0; gap:6px; border:0; border-radius:var(--radius-sm); --btn-bg:transparent; --btn-fg:var(--foreground); text-decoration:underline; text-underline-offset:3px; text-decoration-thickness:1px; }
514
- .btn-link:hover:not(:disabled) { text-decoration-thickness:2px; }
534
+ .btn-link:hover:not(:disabled):not([aria-disabled="true"]) { text-decoration-thickness:2px; }
515
535
  .btn-link-primary { --btn-fg:var(--primary); }
516
536
  [data-theme="light"] .btn-link-primary { --btn-fg:color-mix(in oklab, var(--primary) 45%, var(--foreground)); }
517
537
  .btn-link-danger { --btn-fg:var(--destructive); }
@@ -530,7 +550,7 @@ img,svg { display:block; }
530
550
  "ativa", porque ele também anuncia "página atual" pro leitor de tela. O traço é
531
551
  ::after, pill, alinhado ao padding do texto; posição pelo eixo bloco (não espelha RTL). */
532
552
  .btn-nav { --btn-bg:transparent; --btn-fg:var(--muted-foreground); --btn-border:transparent; }
533
- .btn-nav:hover:not(:disabled) { --btn-fg:var(--foreground); }
553
+ .btn-nav:hover:not(:disabled):not([aria-disabled="true"]) { --btn-fg:var(--foreground); }
534
554
  .btn-icon { width:var(--control-h-md); padding:0; border-radius:var(--radius-md); }
535
555
  .btn-icon.btn-xs { width:var(--control-h-xs); border-radius:var(--radius-sm); }
536
556
  .btn-icon.btn-sm { width:var(--control-h-sm); border-radius:var(--radius-sm); } .btn-icon.btn-lg { width:var(--control-h-lg); border-radius:var(--radius-md); }
@@ -590,6 +610,10 @@ img,svg { display:block; }
590
610
  /* HoverCard (Lote 1) reusa `.popover`; só limita a largura, porque prévia é conteúdo, não rótulo. */
591
611
  .hover-card { max-width:min(20rem,calc(100vw - var(--space-8))); }
592
612
  .input-wrap { position:relative; } .input-wrap>.icon { position:absolute; inset-inline-start:12px; top:50%; transform:translateY(-50%); color:var(--subtle-foreground); pointer-events:none; } .input-wrap .input { padding-inline-start:40px; }
613
+ /* Form (M1): empilhar campos com respiro. Nada além disso — sem borda, sem fundo, sem largura.
614
+ Formulário é ARRANJO, e arranjo é do Stack/Grid; se esta classe crescer, ela vira uma terceira
615
+ maneira de fazer layout e passa a brigar com as duas que já existem. */
616
+ .form { display:grid; gap:var(--space-5); }
593
617
  .field-error { color:var(--danger-400); font-size:var(--text-xs); }
594
618
  .checkbox,.radio { display:inline-flex; align-items:flex-start; gap:9px; color:var(--foreground); cursor:pointer; }
595
619
  .checkbox input,.radio input { position:absolute; opacity:0; pointer-events:none; }
@@ -688,6 +712,10 @@ img,svg { display:block; }
688
712
  @media (max-width:640px) { .banner { grid-template-columns:auto minmax(0,1fr); } .banner>:last-child { grid-column:2; justify-self:start; } }
689
713
  .progress { height:8px; overflow:hidden; border-radius:999px; background:var(--surface-3); }
690
714
  .progress>span { display:block; height:100%; border-radius:inherit; background:var(--primary); }
715
+ /* DataState (M3): a região que troca de cara. Ela NÃO desenha nada próprio — só empilha o que
716
+ já existe (esqueleto, alerta, estado vazio, conteúdo) com respiro entre eles. Se ganhar borda
717
+ ou fundo, viram duas superfícies para a mesma coisa — o defeito que a `.table-region` cobrou. */
718
+ .data-state { display:grid; gap:var(--space-3); }
691
719
  .skeleton { position:relative; overflow:hidden; border-radius:7px; background:var(--surface-3); }
692
720
  .skeleton { animation:skeleton-pulse 1.35s ease-in-out infinite; } @keyframes skeleton-pulse { 50% { opacity:.55; } }
693
721
 
@@ -731,7 +759,16 @@ img,svg { display:block; }
731
759
  tabela; `DataGrid` embrulha em `.table-wrap`; e as 3 tabelas da página legada estão todas
732
760
  dentro de `.table-wrap`. Nenhuma <table> do repositório fica descoberta — o gate de pixel é
733
761
  quem prova, e ele tem de acusar ZERO mudança nas superfícies de tabela. */
734
- .table-wrap { overflow:auto; border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); }
762
+ /* `.table-region` entrou nesta regra em 13/08/2026, e a linha acima ("o gate tem de acusar ZERO
763
+ mudança nas superfícies de tabela") vale para o ESCOPO daquele lote, não para sempre: aqui a
764
+ mudança de superfície é o pedido. O `Table` embrulhava em `.table-region`, que tinha só
765
+ `overflow` e `--radius-lg` — sem borda e sem fundo. Resultado na tela: a tabela aparecia solta
766
+ na página enquanto o `DataGrid`, do lado, tinha a caixa flutuante da marca. Duas peles para a
767
+ mesma coisa, e a do componente mais simples era a errada.
768
+ Somar o seletor em vez de copiar os valores: copiar deixaria duas listas para manter em sincronia,
769
+ que é como as duas peles divergiram. O que continua só do `.table-region` é o foco — ele é
770
+ `tabIndex=0` (região rolável precisa ser alcançável pelo teclado) e o `.table-wrap` não é. */
771
+ .table-wrap,.table-region { overflow:auto; border:1px solid var(--border); border-radius:var(--radius-card); background:var(--card); }
735
772
  .table,.table-wrap table { width:100%; border-collapse:collapse; min-width:720px; }
736
773
  .table th,.table td,.table-wrap th,.table-wrap td { height:var(--row-h); padding:0 14px; text-align:start; border-bottom:1px solid var(--border); }
737
774
  .table th,.table-wrap th { color:var(--subtle-foreground); background:var(--surface-2); font-size:var(--text-xs); letter-spacing:var(--tracking-wider); text-transform:uppercase; }
@@ -760,9 +797,27 @@ img,svg { display:block; }
760
797
  /* DataList: chave/valor em duas colunas. O termo é secundário — mesmo idioma do cabeçalho de
761
798
  tabela. Sem a regra (achado A13) o <dl> saía cru: dt e dd empilhados, com o recuo de 40px
762
799
  que o navegador dá ao <dd>. */
763
- .data-list { display:grid; grid-template-columns:max-content minmax(0,1fr); gap:var(--space-2) var(--space-6); margin:0; }
764
- .data-list dt { color:var(--muted-foreground); }
800
+ /* A coluna do TERMO era `max-content`, que não encolhe nunca: um `dt` comprido empurrava a
801
+ PÁGINA para fora em telas estreitas — medido em 16/08/2026 a 320px, quando a página de hooks
802
+ estreou termos de frase inteira e a varredura acusou +179px de rolagem lateral. `auto` sizes
803
+ igual quando há espaço (por isso nenhuma baseline mudou) e cai para min-content quando não há,
804
+ deixando o termo quebrar em vez de arrastar o documento. O defeito era do COMPONENTE, não da
805
+ página nova: o `DataList` é publicado, e quem escrevesse um termo longo levava o mesmo.
806
+ `auto` foi TENTADO primeiro e não resolveu — medido, não suposto: a trilha `auto` tem
807
+ max-content como máximo e não encolhe abaixo dele quando o contêiner aperta, e a sobra caiu de
808
+ 179px para 90px em vez de zerar. `minmax(0,max-content)` é o que encolhe: com espaço mede
809
+ igual ao que media antes (nenhuma baseline mudou), sem espaço o termo quebra. */
810
+ .data-list { display:grid; grid-template-columns:minmax(0,max-content) minmax(0,1fr); gap:var(--space-2) var(--space-6); margin:0; }
811
+ .data-list dt { min-width:0; color:var(--muted-foreground); }
765
812
  .data-list dd { min-width:0; margin:0; }
813
+ /* E no ESTREITO ele empilha — a outra metade da correção. Medido a 320px com termos de frase
814
+ inteira: duas colunas não cabem, o termo resolvia em 164px, a calha comia o resto e a coluna do
815
+ valor ficava com `0px`, jogando o texto para fora da PÁGINA. Mesmo remédio que `.message` e
816
+ `.log-line` já usam aqui. A regra mora DEPOIS da base de propósito: escrita antes, ela não
817
+ valia nada — mídia não soma especificidade, então a base vencia por vir por último. Foi
818
+ exatamente o que aconteceu na primeira tentativa, e é a armadilha que o comentário do
819
+ `.banner` lá em cima já registrava. */
820
+ @media (max-width:640px) { .data-list { grid-template-columns:minmax(0,1fr); } }
766
821
  /* Timeline: o trilho existia e o PONTO não — `.timeline-dot` media 0×0 (achado A13), então a
767
822
  linha do tempo saía com a régua e sem as marcas, e o <ol> ainda mostrava a numeração do
768
823
  navegador. Agora os dois derivam do MESMO token: o trilho fica a meio diâmetro do ponto, e
@@ -880,7 +935,7 @@ img,svg { display:block; }
880
935
  .calendar-months { position:relative; }
881
936
  .calendar nav { position:absolute; inset-block-start:0; inset-inline:0; display:flex; justify-content:space-between; }
882
937
  .calendar nav button { display:inline-flex; align-items:center; justify-content:center; width:var(--control-h-sm); height:var(--control-h-sm); padding:0; border:0; border-radius:var(--radius-control); background:transparent; color:var(--muted-foreground); cursor:pointer; }
883
- .calendar nav button:hover:not(:disabled) { background:var(--secondary); color:var(--foreground); }
938
+ .calendar nav button:hover:not(:disabled):not([aria-disabled="true"]) { background:var(--secondary); color:var(--foreground); }
884
939
  .calendar nav button:disabled { opacity:.4; cursor:not-allowed; }
885
940
  .calendar nav svg { width:var(--icon-sm); height:var(--icon-sm); fill:currentColor; }
886
941
  .calendar-caption { display:flex; align-items:center; justify-content:center; height:var(--control-h-sm); color:var(--foreground); font-size:var(--text-sm); font-weight:var(--weight-medium); }
@@ -893,7 +948,7 @@ img,svg { display:block; }
893
948
  .calendar th { padding:0 0 var(--space-1); text-align:center; color:var(--muted-foreground); font-size:var(--text-xs); font-weight:var(--weight-regular); }
894
949
  .calendar td { padding:0; text-align:center; }
895
950
  .calendar td button { display:flex; align-items:center; justify-content:center; width:var(--control-h-md); height:var(--control-h-md); border:0; border-radius:var(--radius-control); background:transparent; color:var(--foreground); font-size:var(--text-sm); font-variant-numeric:tabular-nums; cursor:pointer; }
896
- .calendar td button:hover:not(:disabled) { background:var(--secondary); }
951
+ .calendar td button:hover:not(:disabled):not([aria-disabled="true"]) { background:var(--secondary); }
897
952
  .calendar td[data-today] button { font-weight:var(--weight-medium); box-shadow:inset 0 0 0 1px var(--border-strong); }
898
953
  .calendar td[data-selected] button { background:var(--primary); color:var(--primary-foreground); font-weight:var(--weight-medium); box-shadow:none; }
899
954
  .calendar td[data-outside] button { color:var(--subtle-foreground); }
@@ -946,6 +1001,151 @@ img,svg { display:block; }
946
1001
  .media-time { padding:0 7px; color:var(--media-muted); font:var(--text-xs) var(--font-code); white-space:nowrap; }
947
1002
  .media-volume { width:82px; accent-color:var(--primary); }
948
1003
 
1004
+ /* IMAGEM (PLANO-1.0, item L4). A caixa é reservada ANTES do byte chegar — é a mesma razão que o
1005
+ comentário do `--media-ar` acima registra: sem proporção, a imagem mede zero até carregar e a
1006
+ página salta quando ela chega (CLS). O fundo é a superfície do esqueleto, e o bitmap a cobre ao
1007
+ pintar — marcador de carregamento sem uma linha de JavaScript.
1008
+
1009
+ ⚠ NÃO declare `aspect-ratio` aqui, e isto foi MEDIDO em 15/08/2026, não deduzido. A primeira
1010
+ versão desta regra tinha `aspect-ratio:var(--image-ratio,auto)`, e o fallback `auto` PASSA POR
1011
+ CIMA do `aspect-ratio: auto <width> / <height>` que o navegador deriva dos atributos do
1012
+ elemento. Resultado medido numa caixa de 400px: com `width=300 height=200` e sem a prop `ratio`,
1013
+ a imagem saía **400×0** — ou seja, a regra escrita para impedir o salto de layout produzia
1014
+ exatamente o salto. Sem a declaração, o mesmo caso reserva 400×267. Quem tem proporção declarada
1015
+ recebe `aspect-ratio` inline, do componente; quem não tem fica com o comportamento do navegador,
1016
+ que já é o certo. */
1017
+ .image { display:block; width:100%; height:auto; object-fit:cover; border-radius:var(--radius-lg); background:var(--surface-3); }
1018
+ .image-contain { object-fit:contain; background:transparent; }
1019
+ .image-broken { display:grid; place-items:center; color:var(--muted-foreground); }
1020
+
1021
+ /* GALERIA (PLANO-1.0, item L2). A grade se adapta sozinha — `auto-fill` com um mínimo, e não um
1022
+ número de colunas —, porque quem sabe quanta largura existe é o contêiner, não o componente.
1023
+ `--gallery-min` é a válvula, no idioma do `--carousel-slide` e do `--qr-size`.
1024
+ O SELECIONADO NÃO INVENTA LINGUAGEM: o ladrilho recebe `.is-selected`, a mesma classe da aba
1025
+ ativa, do item de lateral e do botão alternado — cápsula elevada, rótulo na cor da marca e o
1026
+ fio amarelo embaixo. É a regra "uma linguagem só" deste arquivo, e por isso aqui não há uma
1027
+ segunda maneira de dizer "este está escolhido". O recuo existe para a cápsula aparecer: com
1028
+ `padding:0` o fundo do selecionado fica exatamente sob a foto e não se vê.
1029
+ Foco também não tem regra própria: a global do topo deste arquivo já desenha o anel, e ele é
1030
+ de cor DIFERENTE da seleção — senão focar e escolher viram o mesmo sinal. */
1031
+ .gallery { display:grid; grid-template-columns:repeat(auto-fill,minmax(var(--gallery-min,8rem),1fr)); gap:var(--space-3); margin:0; padding:0; list-style:none; }
1032
+ .gallery-item { min-width:0; }
1033
+ .gallery-tile { display:grid; gap:var(--space-1); width:100%; padding:var(--space-1); border:0; border-radius:var(--radius-lg); font:inherit; text-align:start; cursor:pointer; }
1034
+ /* `:not(.is-selected)` e não uma regra de selecionado própria, e a diferença foi MEDIDA em
1035
+ 15/08/2026: `.gallery-tile` e `.is-selected` têm a MESMA especificidade, e a do ladrilho vem
1036
+ depois no arquivo — então `background:transparent` matava a cápsula da linguagem da casa e o
1037
+ selecionado saía só com o fio amarelo. Reescrever a cápsula aqui seria a segunda cópia da
1038
+ linguagem "uma linguagem só" existe para impedir; tirar o fundo só de quem NÃO está escolhido
1039
+ deixa a regra de lá governar sem competição. O fundo de botão do navegador precisa morrer de
1040
+ qualquer forma — ele é `buttonface`, não transparente. */
1041
+ .gallery-tile:not(.is-selected) { background:transparent; color:var(--muted-foreground); }
1042
+ .gallery-caption { font-size:var(--text-sm); }
1043
+
1044
+ /* PROSA (PLANO-1.0, item L5). É a PELE do texto longo, não o parser — quem transforma Markdown em
1045
+ elementos é o consumidor. Aqui só se decide como esses elementos se leem.
1046
+
1047
+ ⚠ TODA regra abaixo é ESCOPADA em `.prose`, e isso não é estilo de escrita: é a trava do item, e
1048
+ ela tem uma conta paga atrás. As cinco regras de tabela deste arquivo eram de ELEMENTO e valiam
1049
+ para toda <table> do documento — o calendário nasceu com 720px de largura por causa disso, e
1050
+ nenhum gate viu, porque os checks 15 e 18 comparam CLASSE e seletor de elemento não tem
1051
+ nenhuma. Escrever `blockquote{...}` aqui repetiria o Lote 4 com outro elemento.
1052
+
1053
+ O tamanho sobe para `--text-base`: o corpo do documento é `--text-md` (14px), que serve a
1054
+ interface e é pequeno para ler artigo. A entrelinha é `--leading-relaxed`, que existe no token
1055
+ e não tinha uso. A MEDIDA de linha é `--prose-measure`, no idioma das outras válvulas.
1056
+
1057
+ A FONTE não muda: `--font-editorial` (IBM Plex Serif) existe e está sem uso, e usá-la aqui
1058
+ seria decisão de APARÊNCIA que o BUILDING.md §3.1 manda levar ao Victor com imagem do antes e
1059
+ do depois. Quem quiser serifa na prosa aponta a variável; a Aurea não decide isso sozinha. */
1060
+ .prose { max-width:var(--prose-measure,68ch); font-size:var(--text-base); line-height:var(--leading-relaxed); }
1061
+ .prose > * + * { margin-block-start:var(--space-4); }
1062
+ .prose > h2,.prose > h3,.prose > h4 { margin-block-start:var(--space-8); }
1063
+ .prose h1,.prose h2,.prose h3,.prose h4 { line-height:var(--leading-tight); font-weight:var(--weight-semibold); }
1064
+ .prose h1 { font-size:var(--text-3xl); }
1065
+ .prose h2 { font-size:var(--text-2xl); }
1066
+ .prose h3 { font-size:var(--text-xl); }
1067
+ .prose h4 { font-size:var(--text-lg); }
1068
+ .prose blockquote { margin-inline:0; padding-inline-start:var(--space-4); border-inline-start:2px solid var(--border-strong); color:var(--muted-foreground); }
1069
+ .prose ul,.prose ol { padding-inline-start:var(--space-6); }
1070
+ .prose li + li { margin-block-start:var(--space-2); }
1071
+ /* `0.9em` e não um token: código dentro do texto se mede em relação à LINHA em que está, e um
1072
+ valor absoluto o deixaria maior que o parágrafo dentro de um h2. É o mesmo motivo pelo qual o
1073
+ `.badge` tem `line-height:1` — geometria que depende do contexto se escreve relativa. */
1074
+ .prose code { padding:var(--space-05) var(--space-1); border-radius:var(--radius-xs); background:var(--surface-2); font-family:var(--font-code); font-size:0.9em; }
1075
+ .prose pre { overflow-x:auto; padding:var(--space-4); border:1px solid var(--border); border-radius:var(--radius-card); background:var(--surface-2); }
1076
+ .prose pre code { padding:0; border-radius:0; background:transparent; font-size:var(--text-sm); }
1077
+ .prose img { max-width:100%; height:auto; border-radius:var(--radius-lg); }
1078
+ .prose hr { border:0; border-block-start:1px solid var(--border); }
1079
+ .prose figcaption { color:var(--muted-foreground); font-size:var(--text-sm); }
1080
+ /* A tabela da prosa NÃO é a tabela de dados: sem `min-width:720px`, sem faixa de cabeçalho em
1081
+ caixa alta e sem hover de linha. Uma tabela de três colunas no meio de um artigo não é uma
1082
+ grade — forçá-la a 720px é exatamente o defeito que o calendário sofreu. */
1083
+ .prose table { width:100%; border-collapse:collapse; font-size:var(--text-md); }
1084
+ .prose th,.prose td { padding:var(--space-2) var(--space-3); text-align:start; border-block-end:1px solid var(--border); }
1085
+ .prose th { color:var(--subtle-foreground); font-weight:var(--weight-semibold); }
1086
+
1087
+ /* LISTA ORDENÁVEL (PLANO-1.0, item L3). Duas regras aqui não são decoração e quebram
1088
+ comportamento se saírem:
1089
+ • `touch-action:none` na alça — sem ela o navegador rola a página em vez de deixar arrastar, e
1090
+ o componente não funciona em toque nenhum. É o par obrigatório do `setPointerCapture`;
1091
+ • `cursor:grab`/`grabbing`, que é a única affordance de que aquilo se arrasta.
1092
+ O item PEGO se marca com `data-grabbed`, e o sinal é ELEVAÇÃO e borda — não cor sozinha
1093
+ (WCAG 1.4.1), e não a cápsula de `.is-selected`: pego e escolhido são coisas diferentes e não
1094
+ podem falar a mesma língua. */
1095
+ .sortable-list { display:grid; gap:var(--space-2); margin:0; padding:0; list-style:none; }
1096
+ .sortable-item { display:flex; align-items:center; gap:var(--space-2); padding:var(--space-2) var(--space-3); border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--card); }
1097
+ .sortable-item[data-grabbed] { border-color:var(--border-strong); box-shadow:var(--shadow-lg); }
1098
+ .sortable-handle { display:grid; place-items:center; min-width:var(--space-6); min-height:var(--space-6); padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--muted-foreground); cursor:grab; touch-action:none; }
1099
+ .sortable-handle[aria-pressed="true"] { cursor:grabbing; color:var(--primary); }
1100
+ .sortable-label { min-width:0; }
1101
+
1102
+ /* EDITOR POR BLOCOS (PLANO-1.0, item N1). A Aurea é dona da MOLDURA; o texto rico de dentro é do
1103
+ consumidor — ADR-0025, e o comentário do `inputs.tsx` traz a medição inteira.
1104
+ Duas regras aqui são COMPORTAMENTO e não enfeite, as mesmas da lista ordenável, porque o
1105
+ protocolo de arrasto é o mesmo (`useReorder`):
1106
+ • `touch-action:none` na alça — sem ela o navegador rola a página em vez de deixar arrastar, e
1107
+ o componente não funciona em toque nenhum. É o par obrigatório do `setPointerCapture`;
1108
+ • `cursor:grab`/`grabbing`, a única affordance de que aquilo se arrasta.
1109
+ `min-width:0` no corpo NÃO é enfeite tampouco: sem ele um filho largo (imagem, tabela, bloco de
1110
+ código) estoura a coluna do grid em vez de encolher, e a página ganha rolagem lateral — que é
1111
+ exatamente o que o `catalog-sweep` reprova.
1112
+ O raio é `--radius-lg` e não `--radius-card`: bloco é LINHA de uma lista, no mesmo idioma do
1113
+ `.sortable-item`, e não um cartão flutuante. Sai da identidade que já existe, sem decisão de
1114
+ aparência nova. O bloco PEGO se marca com `data-grabbed`, e o sinal é ELEVAÇÃO e borda — não
1115
+ cor sozinha (WCAG 1.4.1). */
1116
+ .block-editor { display:grid; gap:var(--space-3); margin:0; padding:0; list-style:none; }
1117
+ .block-item { display:grid; grid-template-columns:auto minmax(0,1fr); gap:var(--space-3); padding:var(--space-3); border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--card); }
1118
+ .block-item[data-grabbed] { border-color:var(--border-strong); box-shadow:var(--shadow-lg); }
1119
+ .block-rail { display:grid; grid-auto-rows:min-content; gap:var(--space-1); }
1120
+ .block-handle,.block-remove { display:grid; place-items:center; min-width:var(--space-6); min-height:var(--space-6); padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--muted-foreground); }
1121
+ .block-handle { cursor:grab; touch-action:none; }
1122
+ .block-handle[aria-pressed="true"] { cursor:grabbing; color:var(--primary); }
1123
+ .block-body { min-width:0; }
1124
+
1125
+ /* CARROSSEL (PLANO-1.0, item L1). A pele É o motor: o encaixe, a rolagem por toque, a inércia e
1126
+ as setas de teclado saem de `scroll-snap` num contêiner nativo — o React só descobre em qual
1127
+ slide se está. Por isso estas regras não são decoração, e apagá-las quebra comportamento.
1128
+ `--carousel-slide` é a válvula que faz o caso `multiple` da referência sem uma prop: quantos
1129
+ aparecem por vez é decisão de layout da página, no idioma do `--qr-size` e do `--media-h`.
1130
+ `scroll-behavior:smooth` mora AQUI e não no JavaScript de propósito: `scrollBy` sem `behavior`
1131
+ obedece ao valor computado, e a regra global de `prefers-reduced-motion` deste arquivo já o
1132
+ derruba para `auto` — quem pediu menos movimento recebe menos movimento, sem código novo. */
1133
+ .carousel { display:grid; gap:var(--space-3); }
1134
+ .carousel-track { display:flex; gap:var(--space-3); overflow-x:auto; overflow-y:hidden; scroll-snap-type:inline mandatory; scroll-behavior:smooth; overscroll-behavior-inline:contain; scrollbar-width:none; }
1135
+ .carousel-track::-webkit-scrollbar { width:0; height:0; }
1136
+ /* Sem regra de foco própria: a global do topo deste arquivo já dá o anel, e ela usa
1137
+ `--focus-strong` — que é `--primary` no escuro e `--brand-yellow-foreground` no claro. A versão
1138
+ anterior desta linha fixava `--primary` nos dois e teria trocado a cor do foco num deles. */
1139
+ .carousel-slide { flex:0 0 var(--carousel-slide,100%); min-width:0; scroll-snap-align:start; }
1140
+ .carousel-controls { display:flex; align-items:center; justify-content:center; gap:var(--space-2); }
1141
+ .carousel-dots { display:flex; align-items:center; gap:var(--space-1); }
1142
+ /* 24×24 de ALVO com 8×8 de desenho: abaixo disso é reprovação do WCAG 2.2 AA (2.5.8), e uma fila
1143
+ de pontos é onde esse erro nasce. O ponto vem do ::before para não custar um elemento nem uma
1144
+ classe a mais — o alvo é o botão inteiro, o desenho é o miolo. */
1145
+ .carousel-dot { width:var(--space-6); height:var(--space-6); display:grid; place-items:center; padding:0; border:0; background:transparent; cursor:pointer; }
1146
+ .carousel-dot::before { content:""; width:var(--space-2); height:var(--space-2); border-radius:var(--radius-full); background:var(--border); }
1147
+ .carousel-dot[aria-current="true"]::before { background:var(--primary); }
1148
+
949
1149
  /* ========================================================================== */
950
1150
  /* 08. ÍCONES */
951
1151
  /* ========================================================================== */
@@ -957,10 +1157,28 @@ img,svg { display:block; }
957
1157
  .dialog-backdrop { position:fixed; inset:0; z-index:var(--z-modal); background:var(--overlay); backdrop-filter:blur(5px); }
958
1158
  .dialog { position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); z-index:var(--z-modal); width:min(560px,calc(100vw - 40px)); max-height:calc(100vh - 40px); overflow:auto; padding:24px; border:1px solid var(--border); border-radius:var(--radius-card); background:var(--popover); color:var(--popover-foreground); box-shadow:var(--shadow-lg); }
959
1159
  .dialog>header,.drawer>header { display:flex; align-items:flex-start; justify-content:space-between; gap:16px; margin-bottom:16px; } .dialog-body { display:grid; gap:14px; }
1160
+ /* O ConfirmDialog é o MESMO `.dialog` — não nasce uma segunda superfície flutuante, que seria a
1161
+ pele divergindo como divergiu entre `.table-wrap` e `.table-region`. O que muda é a caixa mais
1162
+ estreita (uma frase e dois botões não precisam de 560px) e o rodapé alinhado ao fim, com o
1163
+ destrutivo por último: a ordem visual é cancelar → agir, e é onde as quatro referências batem. */
1164
+ .dialog-confirm { width:min(420px,calc(100vw - 40px)); }
1165
+ .dialog-confirm>footer { display:flex; justify-content:flex-end; gap:var(--space-2); margin-block-start:var(--space-5); }
960
1166
  .drawer-wrap { position:fixed; inset:0; z-index:var(--z-drawer); display:none; background:var(--overlay); } .drawer-wrap.open { display:block; }
961
1167
  .drawer-backdrop { position:fixed; inset:0; z-index:var(--z-drawer); background:var(--overlay); }
962
1168
  .drawer { position:fixed; top:0; bottom:0; z-index:var(--z-drawer); width:min(480px,92vw); padding:24px; background:var(--surface-1); box-shadow:var(--shadow-lg); overflow:auto; } .drawer-right { right:0; border-left:1px solid var(--border); } .drawer-left { left:0; border-right:1px solid var(--border); }
963
1169
  .toast-stack { position:fixed; inset-inline-end:22px; bottom:22px; z-index:var(--z-toast); width:min(360px,calc(100vw - 44px)); display:flex; flex-direction:column; gap:10px; } .toast { display:flex; align-items:center; gap:11px; padding:14px; border:1px solid var(--border); border-radius:var(--radius-lg); background:var(--popover); color:var(--popover-foreground); box-shadow:var(--shadow-md); transition:opacity .28s var(--ease-standard), transform .28s var(--ease-emphasized); } .toast>:first-child { flex:1; min-width:0; } .toast-text { display:flex; flex-direction:column; gap:2px; min-width:0; } .toast[data-starting-style],.toast[data-ending-style] { opacity:0; transform:translateY(12px); }
1170
+ /* As quatro faces do `AureaToastType`, escritas em 16/08/2026 — elas NÃO existiam, e o tipo
1171
+ publicado não pintava nada. O `system.tsx` emite `toast-${t.type}` desde sempre; classe por
1172
+ template é o ponto CEGO do check 18, que só enxerga classe literal — o mesmo defeito que o
1173
+ `log-${level}` já tinha tido. Varridos os 18 padrões dinâmicos do pacote React: este era o
1174
+ ÚNICO órfão (o `ev-${e.id}` do agents.tsx é `id`, não classe).
1175
+ Mecanismo REUSADO do .alert/.banner, não inventado: borda tingida + fundo semântico. Vêm
1176
+ DEPOIS da base `.toast` de propósito — mesma especificidade, a última regra vence, e é a
1177
+ armadilha que o comentário do .banner já registrava lá em cima. */
1178
+ .toast-info { border-color:color-mix(in srgb,var(--info-400) 38%,var(--border)); background:var(--info-bg); }
1179
+ .toast-success { border-color:color-mix(in srgb,var(--success-400) 38%,var(--border)); background:var(--success-bg); }
1180
+ .toast-warning { border-color:color-mix(in srgb,var(--warning-400) 38%,var(--border)); background:var(--warning-bg); }
1181
+ .toast-danger { border-color:color-mix(in srgb,var(--danger-400) 38%,var(--border)); background:var(--danger-bg); }
964
1182
  /* CommandPaletteShell (Fase 11, achado A13). A superfície já existia aqui sob o nome
965
1183
  `.command` — e `.command` é chrome da página de docs manual: nenhum componente React a
966
1184
  emite. Ela passava no check 15 por ACIDENTE, porque o rótulo padrão "Type a command…" põe
@@ -977,6 +1195,18 @@ img,svg { display:block; }
977
1195
  .menu-item { display:flex; align-items:center; gap:10px; width:100%; min-height:var(--control-h-md); padding:0 10px; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--foreground); font:inherit; text-align:start; cursor:pointer; }
978
1196
  .menu-item[data-highlighted],.menu-item:hover:not([data-disabled]) { background:var(--surface-3); outline:none; }
979
1197
  .menu-item[data-disabled] { opacity:.5; cursor:not-allowed; }
1198
+ /* CommandPalette (M6): a lista dentro da paleta. Reusa `.menu` e `.menu-item` — a paleta nao
1199
+ inventa uma segunda pele de lista, que e o defeito que a `.table-region` cobrou caro. O que se
1200
+ acrescenta e o teto de altura (a lista rola, a caixa nao cresce sem fim) e a linha do item,
1201
+ que tem icone, rotulo que se estica e atalho no fim.
1202
+ DEPOIS do `.menu-item` de proposito: as duas regras tem a MESMA especificidade, entao quem vem
1203
+ por ultimo vence. Escrita antes, a grade de tres colunas era apagada pelo `display:flex` do
1204
+ menu — medido em 13/08/2026, e o gate de pele foi quem pegou. */
1205
+ .command-positioner { inline-size:var(--anchor-width); }
1206
+ .command-list { max-height:min(50vh,360px); overflow-y:auto; overscroll-behavior:contain; }
1207
+ .command-item { display:grid; grid-template-columns:auto minmax(0,1fr) auto; gap:var(--space-3); align-items:center; }
1208
+ .command-item-label { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
1209
+
980
1210
  .menu-sep { height:1px; margin:6px 4px; background:var(--border); border:0; }
981
1211
  /* Combobox: reaproveita .menu/.menu-item; só dimensionamento e a coluna do check são próprios.
982
1212
  --anchor-width e --available-height vêm do positioner do Base UI. */
@@ -993,6 +1223,10 @@ img,svg { display:block; }
993
1223
  .combobox-multi:hover { border-color:var(--border); }
994
1224
  .combobox-multi:focus-within { outline:2px solid var(--focus-strong); outline-offset:2px; border-color:var(--focus-strong); }
995
1225
  .combobox-multi>.combobox-actions { position:static; inset-inline-end:auto; }
1226
+ /* o campo de chips não é `.input`, então a regra de :disabled dos campos não o alcança. Quem
1227
+ marca aqui é o `data-disabled` que o Base UI põe no InputGroup a partir do estado da Root. */
1228
+ .combobox-multi[data-disabled] { opacity:.5; cursor:not-allowed; }
1229
+ .combobox-multi[data-disabled] .combobox-chip-input { cursor:not-allowed; }
996
1230
  .combobox-chips { display:flex; flex:1; flex-wrap:wrap; align-items:center; gap:var(--space-2); min-width:0; }
997
1231
  .combobox-chip { display:inline-flex; align-items:center; gap:var(--space-1); padding-block:var(--space-1); padding-inline:var(--space-3) var(--space-1); background:var(--secondary); color:var(--foreground); border-radius:var(--radius-control); font-size:var(--text-sm); }
998
1232
  .combobox-chip-remove { display:inline-flex; padding:0; border:0; background:transparent; color:var(--muted-foreground); border-radius:var(--radius-full); cursor:pointer; }
@@ -1380,7 +1614,9 @@ button.graph-node-body { cursor:pointer; }
1380
1614
 
1381
1615
  /* Aurea v1.7 stabilization patch — visual design unchanged. */
1382
1616
  .badge-running{background:var(--success-bg);color:var(--success-400);border-color:color-mix(in oklab,var(--success-400) 32%,transparent)}
1383
- .table-region{overflow:auto;outline:none;border-radius:var(--radius-lg)}
1617
+ /* superfície (overflow, borda, fundo, raio) mora junto com a do `.table-wrap` lá em cima — aqui
1618
+ fica só o que é DESTA região: ela é focável, e o anel dela é o box-shadow abaixo. */
1619
+ .table-region{outline:none}
1384
1620
  .table-region:focus-visible{box-shadow:0 0 0 3px color-mix(in oklab,var(--focus) 38%,transparent)}
1385
1621
  /* CONTAINER QUERY, e não breakpoint de viewport — Parte D, item D3 (08/08/2026).
1386
1622
  Era `@media (max-width:400px)`, o último dos seis legados do achado M13. Trocar por um degrau
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurea-uds/core",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "The Aurea UDS stylesheet and its vanilla behaviour. Import @aurea-uds/fonts/css before this.",
5
5
  "keywords": ["aurea", "design-system", "css", "design-tokens"],
6
6
  "license": "Apache-2.0",