Files
amare/resources/css/app.css
Manoel Freitas 63c0269489 feat: aplicar identidade Heritage Editorial ao painel Filament (MAN-118) (#40)
* feat: aplicar identidade Heritage Editorial ao painel Filament

O painel admin ainda usava os defaults de fábrica do Filament (Amber,
Zinc, Inter Variable, dark mode ligado) enquanto o site público já
seguia o design system Heritage Editorial há várias entregas — a
inconsistência ficava evidente para quem navegava entre as duas áreas
e não havia nenhum teste travando a configuração do painel.

- Cores primary/gray/danger/warning/success viram arrays explícitos de
  11 tons (não Color::hex()/string), a única forma de preservar os
  hexadecimais exatos do DESIGN.md — Color::hex() decompõe a cor e
  remonta lightness/chroma por uma tabela fixa, perdendo a cor real.
  Os tons foram escolhidos verificando empiricamente com
  ButtonComponentColorMap qual shade o botão sólido realmente usa
  (600/500/50), e o tom 50 do primary é um verde-oliva claro (não
  branco puro) porque BadgeComponent usa bg-color-50 diretamente e um
  branco puro tornaria o badge quase invisível sobre o Papel Marfim.
- EB Garamond self-hosted via LocalFontProvider (sans/mono/serif), sem
  reintroduzir uma requisição externa ao fonts.bunny.net — o hook
  HEAD_END reaproveita o mesmo <x-fonts /> do site público.
- Novo tema Vite (resources/css/filament/admin/theme.css) zera radius
  e shadow só no escopo do Filament, incluindo a variável --radius
  "bare" (usada em ~227 regras do próprio Filament) e um override
  manual para o CSS pré-compilado do tooltip Tippy.js, que não é
  alcançado pelo @theme.
- Dark mode desativado: o Heritage Editorial é uma paleta única.
- Teste de regressão (AdminPanelBrandParityTest) pinando cores, fontes
  e configuração do tema, incluindo uma renderização real de
  /admin/login — foi essa renderização que pegou um bug real: passar
  a família já entre aspas simples quebrava a declaração CSS
  (--font-family: ''EB Garamond''), silenciosamente caindo para
  ui-sans-serif.

Bundle público verificado byte a byte: nenhuma declaração CSS
existente mudou de valor (apenas classes novas e não usadas pelo site
público foram adicionadas ao app.css, um efeito colateral inerte de
ter uma segunda entrada Tailwind no mesmo build do Vite).

Co-Authored-By: Claude noreply@anthropic.com
AI-Assisted: yes
AI-Tool: claude-code

* fix(build): copiar CSS do Filament no estágio frontend e neutralizar sombras

Dois defeitos encontrados ao revisar a paridade visual do painel.

O primeiro impedia o build da imagem. O `resources/css/filament/admin/
theme.css` importa o CSS não compilado do próprio Filament, e o estágio
`frontend` do Dockerfile copia apenas `package.json`, `vite.config.js`,
`resources` e `public` — nunca `vendor`. O `npm run build` falhava na
resolução do import, o que derrubaria os jobs `container` e `browser` do
CI. Agora a subárvore `vendor/filament` é copiada do estágio do composer,
em vez de todo o `vendor`, para manter o contexto pequeno.

O segundo é silencioso e mais interessante. O plugin do Tailwind compartilha
um único contexto entre todas as entradas do build, então o `@source
app/Filament/**` da entrada do painel torna visível o uso de `shadow-*`
do Filament e o Tailwind passa a emitir seus valores padrão de
`--shadow-sm/md/lg` também no bundle público. Verificado por diff do
`app.css` construído com e sem a entrada do tema.

Nada no site público usa utilitário de sombra hoje, então a renderização
não muda e os baselines visuais seguem válidos. Mas deixar valores reais
de sombra definidos no CSS que vai para produção permitiria que um
`shadow-sm` futuro em elemento público violasse a Tonal Layer Rule do
DESIGN.md em silêncio — e o HeritageEditorialTokensTest só inspeciona
arquivos de origem, então não pegaria.

Os tokens de sombra passam a ser fixados em transparente no `@theme` do
`app.css`, com teste que falha se algum deixar de ser. A regra continua
verdadeira no artefato que realmente ship.

Co-Authored-By: Claude noreply@anthropic.com
AI-Assisted: yes
AI-Tool: claude-code

---------

Co-authored-by: manoel.neto <manoel.neto@creditas.com>
2026-08-10 11:09:01 -03:00

342 lines
11 KiB
CSS

@import 'tailwindcss';
@import './tokens.css';
@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php';
@source '../../storage/framework/views/*.php';
@source '../views/**/*.blade.php';
@theme {
--font-sans: var(--amare-font-sans);
--font-serif: var(--amare-font-serif);
--text-xs: var(--amare-text-xs);
--text-sm: var(--amare-text-sm);
--text-base: var(--amare-text-base);
--text-lg: var(--amare-text-lg);
--text-xl: var(--amare-text-xl);
--text-2xl: var(--amare-text-2xl);
--text-3xl: var(--amare-text-3xl);
--text-4xl: var(--amare-text-4xl);
--text-display: clamp(3rem, 7.7vw, 5.875rem);
--text-display--line-height: 0.94;
--text-display--letter-spacing: -0.01em;
--text-headline: clamp(2.375rem, 5.2vw, 4rem);
--text-headline--line-height: 1.02;
--spacing-1: var(--amare-space-1);
--spacing-2: var(--amare-space-2);
--spacing-3: var(--amare-space-3);
--spacing-4: var(--amare-space-4);
--spacing-6: var(--amare-space-6);
--spacing-8: var(--amare-space-8);
--spacing-12: var(--amare-space-12);
--spacing-16: var(--amare-space-16);
--radius-sm: var(--amare-radius-sm);
--radius-md: var(--amare-radius-md);
--radius-lg: var(--amare-radius-lg);
--radius-xl: var(--amare-radius-xl);
--radius-full: var(--amare-radius-full);
--color-amare-bg: var(--amare-color-bg);
--color-amare-bg-deep: var(--amare-color-bg-deep);
--color-amare-bg-archive: var(--amare-color-bg-archive);
--color-amare-bg-muted: var(--amare-color-bg-muted);
--color-amare-text: var(--amare-color-text);
--color-amare-muted: var(--amare-color-muted);
--color-amare-text-muted: var(--amare-color-text-muted);
--color-amare-border: var(--amare-color-border);
--color-amare-accent: var(--amare-color-accent);
--color-amare-accent-deep: var(--amare-color-accent-deep);
--color-amare-accent-hover: var(--amare-color-accent-hover);
--color-amare-sage: var(--amare-color-sage);
--color-amare-accent-text: var(--amare-color-accent-text);
--color-amare-success: var(--amare-color-success);
--color-amare-warning: var(--amare-color-warning);
--color-amare-error: var(--amare-color-error);
--ease-amare: var(--amare-ease-standard);
--default-transition-duration: var(--amare-duration-normal);
/* Neutralised, not omitted. Tailwind's Vite plugin shares one context
* across every entry in the build, so the Filament theme entry's
* `@source app/Filament/**` makes Filament's `shadow-*` usage visible and
* Tailwind then emits its DEFAULT --shadow-sm/md/lg into this public
* bundle too — verified by diffing the built app.css with and without
* that entry. Nothing public uses a shadow utility today, so rendering is
* unchanged either way, but leaving real shadow values defined here would
* let a future `shadow-sm` on a public element silently violate
* DESIGN.md's Tonal Layer Rule, and HeritageEditorialTokensTest only
* inspects source files, so it would not catch it. Zeroing them keeps the
* rule true in the artifact that actually ships. */
--shadow-2xs: 0 0 #0000;
--shadow-xs: 0 0 #0000;
--shadow-sm: 0 0 #0000;
--shadow: 0 0 #0000;
--shadow-md: 0 0 #0000;
--shadow-lg: 0 0 #0000;
--shadow-xl: 0 0 #0000;
--shadow-2xl: 0 0 #0000;
--shadow-inner: 0 0 #0000;
}
@layer base {
body {
background-color: var(--amare-color-bg);
color: var(--amare-color-text);
font-family: var(--amare-font-serif);
overflow-wrap: break-word;
}
[id$='-heading'] {
scroll-margin-top: 5.5rem;
}
a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
outline: 2px solid var(--amare-color-accent);
outline-offset: 3px;
}
}
@utility container-amare {
width: 100%;
max-width: var(--amare-container-max);
margin-inline: auto;
padding-inline: var(--amare-container-padding);
}
@utility img-editorial {
filter: saturate(0.88) contrast(0.96);
}
@utility honeypot {
position: absolute;
left: -9999px;
width: 1px;
height: 1px;
overflow: hidden;
}
@layer components {
.main-nav.is-open {
display: flex;
}
.home-chapters {
counter-reset: home-chapter -1;
}
.home-chapter {
counter-increment: home-chapter;
}
.home-folio {
display: flex;
align-items: center;
gap: 0.5rem;
color: var(--amare-color-accent);
font-size: var(--amare-text-xs);
font-weight: 600;
letter-spacing: 0.14em;
line-height: 1;
text-transform: uppercase;
}
.home-folio--inverse {
color: color-mix(in srgb, var(--amare-color-accent-text) 82%, transparent);
}
.home-folio__separator {
color: var(--amare-color-sage);
}
.home-folio--inverse .home-folio__separator {
color: color-mix(in srgb, var(--amare-color-accent-text) 55%, transparent);
}
.home-folio__number::before {
content: counter(home-chapter, decimal-leading-zero);
font-variant-numeric: tabular-nums;
}
@media (prefers-reduced-motion: no-preference) {
.main-nav {
transition: opacity var(--amare-duration-normal) var(--amare-ease-standard);
}
}
body.menu-open {
overflow: hidden;
}
main {
overflow-x: clip;
}
/* Dossiê vivo — content visible by default; enhance only when opted in */
[data-chapter-index] {
display: none;
}
[data-chapter-progress] {
display: none;
pointer-events: none;
}
[data-chapter-index] a[aria-current="true"] {
color: var(--amare-color-accent-deep);
}
[data-chapter-index] a[aria-current="true"]::before {
content: '';
position: absolute;
left: 0;
top: 0.35em;
bottom: 0.35em;
width: 1px;
background: var(--amare-color-accent);
}
[data-chapter-progress] > span {
display: block;
height: 100%;
width: var(--chapter-progress, 0%);
background: var(--amare-color-accent);
transform-origin: left center;
}
@media (min-width: 1280px) {
[data-chapter-index] {
display: flex;
position: fixed;
top: 50%;
right: max(1rem, calc((100vw - var(--amare-container-max)) / 2 - 7.5rem));
z-index: 30;
max-width: 6.5rem;
translate: 0 -50%;
flex-direction: column;
gap: 0.75rem;
}
[data-chapter-index] a {
position: relative;
display: inline-flex;
align-items: center;
min-height: 2.75rem;
padding-left: 0.75rem;
font-size: var(--amare-text-xs);
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--amare-color-muted);
text-decoration: none;
overflow-wrap: break-word;
transition: color var(--amare-duration-fast) var(--amare-ease-standard);
}
[data-chapter-index] a:hover {
color: var(--amare-color-accent);
}
}
@media (max-width: 1279px) {
[data-chapter-progress] {
display: block;
position: fixed;
top: 0;
left: 0;
z-index: 45;
width: 100%;
height: 2px;
background: transparent;
}
}
@media (prefers-reduced-motion: no-preference) {
:where(a, button, input, textarea, select) {
transition-duration: var(--amare-motion-feedback);
transition-property: color, background-color, border-color, transform;
transition-timing-function: var(--amare-ease-arrival);
}
:where(a, button:not(:disabled)):active {
transform: translateY(1px);
}
/* Transform/clip only — never fade text opacity (axe + WCAG mid-transition). */
html[data-motion="enhance"] [data-motion="page-open"]:not(.is-active) [data-motion-beat] {
transform: translateY(var(--amare-motion-distance-y));
}
html[data-motion="enhance"] [data-motion="page-open"]:not(.is-active) [data-motion-beat="media"] {
clip-path: inset(4% 0 0 0);
}
html[data-motion="enhance"] [data-motion="page-open"].is-active [data-motion-beat] {
transform: none;
clip-path: inset(0 0 0 0);
transition:
transform var(--amare-motion-enter) var(--amare-ease-arrival),
clip-path var(--amare-motion-enter) var(--amare-ease-arrival);
transition-delay: min(
calc(var(--motion-index, 0) * var(--amare-motion-stagger)),
var(--amare-motion-stagger-cap)
);
}
html[data-motion="enhance"] [data-reveal] {
--motion-translate-x: 0;
--motion-translate-y: var(--amare-motion-distance-y);
}
html[data-motion="enhance"] [data-reveal-from="left"] {
--motion-translate-x: calc(-1 * var(--amare-motion-distance-x-mobile));
--motion-translate-y: 0;
}
html[data-motion="enhance"] [data-reveal-from="right"] {
--motion-translate-x: var(--amare-motion-distance-x-mobile);
--motion-translate-y: 0;
}
@media (min-width: 768px) {
html[data-motion="enhance"] [data-reveal-from="left"] {
--motion-translate-x: calc(-1 * var(--amare-motion-distance-x));
}
html[data-motion="enhance"] [data-reveal-from="right"] {
--motion-translate-x: var(--amare-motion-distance-x);
}
}
html[data-motion="enhance"] [data-reveal]:not(.is-revealed) {
transform: translate3d(var(--motion-translate-x), var(--motion-translate-y), 0);
}
html[data-motion="enhance"] [data-reveal][data-reveal-media]:not(.is-revealed) {
clip-path: inset(3% 0 0 0);
}
html[data-motion="enhance"] [data-reveal-group] [data-reveal].is-revealed,
html[data-motion="enhance"] [data-reveal].is-revealed {
transform: none;
clip-path: inset(0 0 0 0);
transition:
transform var(--amare-motion-enter) var(--amare-ease-arrival),
clip-path var(--amare-motion-enter) var(--amare-ease-arrival);
transition-delay: min(
calc(var(--motion-index, 0) * var(--amare-motion-stagger)),
var(--amare-motion-stagger-cap)
);
}
}
}