/* * 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. */ .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 { padding: 8px 16px; color: #fff; border-color: rgba(255, 255, 255, 0.38); background: transparent; } @media (hover: hover) { & .ds-link.ds-link-muted:hover { border-color: #fff; box-shadow: none; } } & .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; 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; } }