Hero e movimento - cena 3D em tempo real com os blocos da marca (kit feito no Blender, 3d/blocos.py): marca, tela, integrações e dados; segue a rolagem, tem vida em repouso, reage ao cursor e, parada no topo, passa sozinha pelos estados com legenda - três níveis de aparelho (full, lite, static); sem WebGL fica o pôster - título novo: "Sites e sistemas sob medida para o jeito que a sua empresa trabalha." - faixa de clientes com o ramo, linha do primeiro passo, hero alinhado às seções - rótulos digitados, entrada dos blocos, cortina de blocos entre páginas e capa compartilhada entre a lista de cases e o case Ofertas - atendimento no WhatsApp com IA e nota fiscal para a reforma tributária (páginas de serviço, cartões da home, formulário e aviso com data de validade) - página /ia atualizada, com fontes - peças 3D em loop nos cartões e topos de página (3d/pecas.py) Design - hover por papel (bloco nos botões, barra nos links), rótulos sem caixa alta - um destino por rótulo: "Falar sobre meu projeto" leva ao formulário, "Chamar no WhatsApp" abre o WhatsApp - logo montado em blocos, 404 redesenhado, grades sem célula vazia - ícones do PWA e manifesto novos Specs em specs/, contexto de design em DESIGN.md e PRODUCT.md.
333 lines
8.6 KiB
CSS
333 lines
8.6 KiB
CSS
/*
|
|
* Lista de projetos e o que a vitrine fixa divide com ela (legenda, título, botões), mais o casco `.ds-reel` e o
|
|
* bloco que segura o lugar da vitrine antes de o navegador montar a página. Vem dentro do global (app/globals.css o
|
|
* importa), para a home não carregar uma terceira folha bloqueante; nenhum componente a importa. A vitrine fixa
|
|
* (pinned-reel.css) e a janela ampliada (lightbox.css) vêm sob demanda, com seus
|
|
* componentes; as molduras de navegador e de celular, que o hero e os cases também usam, ficam em showcase.css
|
|
* (global). Cantos retos, rótulos curtos em mono (12 px no mínimo), texto de botão em sans 15 px, lima só em
|
|
* detalhes (nenhum botão preenchido de lima aqui: isso é da ação de contato) e a cor do site de cada projeto
|
|
* (--accent) só no brilho ao redor do vídeo.
|
|
*/
|
|
|
|
/* ─────────────────────────── Casco da vitrine fixa ─────────────────────────── */
|
|
|
|
.ds-reel {
|
|
--pin-h: calc(100svh - var(--site-header-height));
|
|
position: relative;
|
|
margin-top: var(--sp-16);
|
|
/* a cena fica presa durante (soma dos pesos) alturas de tela de rolagem */
|
|
height: calc(var(--pin-h) + var(--reel-sum, 1) * 100svh);
|
|
}
|
|
|
|
/* tela baixa (celular deitado, janela de desktop curta): a vitrine fixa não cabe, e a lista de projetos entra no lugar */
|
|
@media (max-height: 560px) {
|
|
.ds-reel {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/* antes de o navegador montar a página, só onde a vitrine fixa vai existir: o bloco reservado aparece e a lista
|
|
(que o servidor entregou, com o texto e os links) fica escondida; sem JavaScript, a lista é quem aparece */
|
|
.ds-reel-placeholder {
|
|
display: none;
|
|
}
|
|
|
|
@media (min-width: 768px) and (min-height: 561px) and (
|
|
prefers-reduced-motion: no-preference
|
|
) and (scripting: enabled) {
|
|
.ds-reel-placeholder {
|
|
display: block;
|
|
}
|
|
|
|
.ds-reel-list[data-pending] {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/* ─────────────────────────── Legenda e botões de um projeto ─────────────────────────── */
|
|
|
|
/* uma só legenda para o projeto em cena: na troca ela some depressa (120 ms, o mesmo CAPTION_OUT_MS de
|
|
ProjectReel.tsx) e volta com o conteúdo novo; só opacidade, o texto nunca se desloca */
|
|
.ds-reel-caption {
|
|
flex: none;
|
|
display: grid;
|
|
gap: 6px;
|
|
min-width: 0;
|
|
transition: opacity 0.2s ease-out;
|
|
|
|
&[data-leaving] {
|
|
opacity: 0;
|
|
pointer-events: none;
|
|
transition: opacity 0.12s linear;
|
|
}
|
|
}
|
|
|
|
.ds-reel-title {
|
|
font-family: var(--font-display);
|
|
font-size: clamp(22px, 3vw, 38px);
|
|
font-weight: var(--fw-card);
|
|
line-height: 1.02;
|
|
letter-spacing: -0.03em;
|
|
color: #fff;
|
|
}
|
|
|
|
.ds-reel-sub {
|
|
font-size: 15px;
|
|
line-height: 1.5;
|
|
color: rgba(255, 255, 255, 0.68);
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* Ver case e Ampliar vídeo em contorno; Abrir site é link de texto. Nada em lima: o preenchido é do contato. No
|
|
ponteiro e no foco, o bloco translúcido dos contornos em fundo escuro (globals.css). */
|
|
.ds-reel-actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: var(--sp-2) var(--sp-3);
|
|
margin-top: var(--sp-2);
|
|
|
|
& .ds-link.ds-link-muted {
|
|
--block: rgba(255, 255, 255, 0.12);
|
|
padding: 8px 16px;
|
|
color: #fff;
|
|
border-color: rgba(255, 255, 255, 0.38);
|
|
background: transparent;
|
|
}
|
|
|
|
& .ds-link.ds-link-muted:focus-visible {
|
|
border-color: rgba(255, 255, 255, 0.55);
|
|
}
|
|
|
|
@media (hover: hover) {
|
|
& .ds-link.ds-link-muted:hover {
|
|
border-color: rgba(255, 255, 255, 0.55);
|
|
}
|
|
}
|
|
|
|
& .ds-link.ds-link-text {
|
|
color: rgba(255, 255, 255, 0.84);
|
|
}
|
|
}
|
|
|
|
.ds-reel-expand {
|
|
cursor: pointer;
|
|
|
|
& svg {
|
|
flex: none;
|
|
width: 16px;
|
|
height: 16px;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1.6;
|
|
}
|
|
}
|
|
|
|
/* janela curta: sem o subtítulo a legenda cabe em menos altura */
|
|
@media (min-width: 640px) and (max-height: 700px) {
|
|
.ds-reel-sub {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.ds-reel {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/* ─────────────────────────── Lista de projetos ─────────────────────────── */
|
|
|
|
/*
|
|
* Sem rolagem presa: celular, movimento reduzido e janelas baixas. No celular é um carrossel por toque
|
|
* (rolagem horizontal com encaixe; o card seguinte aparece pela borda); acima de 768 px, uma grade.
|
|
*/
|
|
.ds-reel-list {
|
|
margin-top: var(--sp-10);
|
|
}
|
|
|
|
.ds-reel-items {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr));
|
|
gap: var(--sp-8) var(--sp-6);
|
|
list-style: none;
|
|
}
|
|
|
|
.ds-reel-item {
|
|
--accent: var(--slash);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--sp-5);
|
|
min-width: 0;
|
|
}
|
|
|
|
.ds-reel-item-media {
|
|
position: relative;
|
|
isolation: isolate;
|
|
|
|
&::before {
|
|
content: "";
|
|
position: absolute;
|
|
inset: -4% 0;
|
|
z-index: -1;
|
|
background: radial-gradient(
|
|
55% 60% at 50% 50%,
|
|
color-mix(in srgb, var(--accent) 36%, transparent),
|
|
transparent 72%
|
|
);
|
|
opacity: 0.4;
|
|
pointer-events: none;
|
|
}
|
|
}
|
|
|
|
.ds-reel-item-screen {
|
|
position: relative;
|
|
aspect-ratio: 16 / 10;
|
|
overflow: hidden;
|
|
background: #0a0a0a;
|
|
|
|
& > img {
|
|
display: block;
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
object-position: top;
|
|
}
|
|
}
|
|
|
|
.ds-reel-item-phone {
|
|
width: min(62%, 240px);
|
|
margin-inline: auto;
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
.ds-reel-list {
|
|
margin-top: var(--sp-8);
|
|
}
|
|
|
|
.ds-reel-items {
|
|
display: flex;
|
|
gap: var(--sp-4);
|
|
overflow-x: auto;
|
|
overscroll-behavior-x: contain;
|
|
scroll-snap-type: x mandatory;
|
|
scroll-padding-inline: var(--sp-5);
|
|
scrollbar-width: none;
|
|
/* o card seguinte aparece pela borda: é o convite para deslizar */
|
|
margin-inline: calc(var(--sp-5) * -1);
|
|
padding: 2px var(--sp-5) var(--sp-4);
|
|
}
|
|
|
|
.ds-reel-items::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
.ds-reel-item {
|
|
flex: 0 0 min(82%, 340px);
|
|
scroll-snap-align: start;
|
|
/* um deslize rápido para em cada cartão, em vez de pular projetos */
|
|
scroll-snap-stop: always;
|
|
padding: var(--sp-5) var(--sp-4);
|
|
background: rgba(255, 255, 255, 0.03);
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
/* um cartão mais baixo: sem subtítulo a legenda cabe e o celular da moldura ganha espaço; texto corrido em 15 px */
|
|
.ds-reel-item .ds-reel-sub {
|
|
font-size: 15px;
|
|
-webkit-line-clamp: 3;
|
|
}
|
|
}
|
|
|
|
/* sem JavaScript o carrossel vira lista vertical: nada fica escondido atrás de uma rolagem lateral */
|
|
@media (scripting: none) {
|
|
.ds-reel-items {
|
|
display: grid;
|
|
overflow: visible;
|
|
margin-inline: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.ds-reel-item {
|
|
flex: none;
|
|
}
|
|
}
|
|
|
|
/* ─────────────────────────── Carrossel do celular: contagem e botões ─────────────────────────── */
|
|
|
|
.ds-reel-count {
|
|
display: none;
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
/* "1/4" e pontos logo abaixo do carrossel: quantos há e em qual se está */
|
|
.ds-reel-count {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: var(--sp-3);
|
|
margin-top: var(--sp-1);
|
|
font-family: var(--font-mono);
|
|
font-size: 12px;
|
|
letter-spacing: 0.08em;
|
|
color: rgba(255, 255, 255, 0.72);
|
|
}
|
|
|
|
.ds-reel-dots {
|
|
display: flex;
|
|
gap: 6px;
|
|
|
|
& i {
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
background: rgba(255, 255, 255, 0.24);
|
|
transition: background 0.2s ease;
|
|
}
|
|
|
|
& i[data-on] {
|
|
background: var(--slash);
|
|
}
|
|
}
|
|
|
|
/* botões alinhados em todos os cartões: "Ver case" em largura total, "Ampliar" só com o ícone (44 px, o alvo de
|
|
toque mínimo) ao lado, e "Abrir site" numa linha só dele */
|
|
.ds-reel-item .ds-reel-actions {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
gap: var(--sp-2) 0;
|
|
margin-top: var(--sp-3);
|
|
|
|
& .ds-link.ds-link-muted:not(.ds-reel-expand) {
|
|
width: 100%;
|
|
}
|
|
|
|
& .ds-reel-expand {
|
|
width: 44px;
|
|
margin-left: var(--sp-2);
|
|
padding: 0;
|
|
}
|
|
|
|
& .ds-link-text {
|
|
grid-column: 1 / -1;
|
|
justify-self: start;
|
|
}
|
|
}
|
|
|
|
/* o rótulo sai da vista mas não do leitor de tela (mesma técnica do .sr-only) */
|
|
.ds-reel-item .ds-reel-expand-label {
|
|
position: absolute;
|
|
width: 1px;
|
|
height: 1px;
|
|
margin: -1px;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
clip-path: inset(50%);
|
|
white-space: nowrap;
|
|
border: 0;
|
|
}
|
|
}
|