perf(movimento): sem tempo morto, vídeos regravados e 3D sem React Three Fiber

Legenda do mergulho até Projetos cobrir a cena; transição de página sem blur e com fundo escuro; foco no conteúdo ao trocar de página; listas com marcador e dois pesos de título; vídeos da SEV e da SC Plus regravados sem quadros brancos; scrub a 12-15 fps (-30%); vitrine com uma parada de Tab e setas, contador no celular e CSS sob demanda; âncoras num módulo só (fragment-nav); FramePulse com setInterval; CSS morto removido.
This commit is contained in:
Evandro Fonseca Junior committed 2026-10-14 17:01:37 -03:00
1 parent f8545cd442
commit 6ac87824f3
68 files changed
+5735 -3300

No files matched your search

+382
View File
@@ -0,0 +1,382 @@
/*
* Vitrine animada (ProjectReel mostra a fixa quando ela cabe): o site de cada projeto rola dentro de um notebook (e de
* um celular ao lado) conforme a página rola. Carrega sob demanda, junto com PinnedReel; o casco `.ds-reel`, a legenda
* e os botões vêm de reel-list.css.
*/
.ds-reel-pin {
position: sticky;
top: var(--site-header-height);
height: var(--pin-h);
overflow: clip;
}
.ds-reel-grid {
display: grid;
grid-template-columns: minmax(0, 1fr);
grid-template-rows: auto minmax(0, 1fr);
gap: var(--sp-4);
height: 100%;
padding-block: var(--sp-4);
}
@media (min-width: 1024px) {
.ds-reel-grid {
grid-template-columns: minmax(190px, 250px) minmax(0, 1fr);
grid-template-rows: minmax(0, 1fr);
gap: var(--sp-10);
padding-block: var(--sp-6);
}
}
/* lista de projetos: faixa rolável na horizontal em telas pequenas, coluna no desktop */
.ds-reel-index {
min-width: 0;
& > ol {
display: flex;
gap: 8px;
list-style: none;
overflow-x: auto;
scrollbar-width: none;
}
& > ol::-webkit-scrollbar {
display: none;
}
}
.ds-reel-pick {
position: relative;
display: flex;
align-items: center;
gap: 10px;
min-height: 44px;
padding: 0 14px;
font-family: var(--font-display);
font-size: 15px;
font-weight: 500;
white-space: nowrap;
color: rgba(255, 255, 255, 0.72);
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.12);
cursor: pointer;
transition:
color 0.25s ease,
border-color 0.25s ease,
background 0.25s ease;
@media (hover: hover) {
&:hover {
color: #fff;
border-color: rgba(255, 255, 255, 0.3);
}
}
&[aria-current="true"] {
color: #fff;
border-color: rgba(255, 255, 255, 0.6);
background: rgba(255, 255, 255, 0.08);
}
}
.ds-reel-hint {
display: none;
align-items: center;
flex-wrap: wrap;
gap: 6px 10px;
margin-bottom: var(--sp-5);
font-family: var(--font-mono);
font-size: 12px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--slash);
}
.ds-reel-hint-line {
width: 24px;
height: 1px;
background: var(--slash);
}
.ds-reel-hint-sub {
width: 100%;
color: rgba(255, 255, 255, 0.5);
}
.ds-reel-num {
font-family: var(--font-mono);
font-size: 12px;
color: var(--slash);
&::before {
content: attr(data-n);
}
}
.ds-reel-name {
display: none;
}
/* trechos do projeto em cena: só no desktop, onde sobra coluna; cada um leva ao ponto do vídeo */
.ds-reel-chapters {
display: none;
list-style: none;
margin: 6px 0 10px 16px;
border-left: 1px solid rgba(255, 255, 255, 0.12);
}
.ds-reel-chapter-pick {
display: flex;
align-items: center;
width: 100%;
min-height: 32px;
gap: 10px;
padding: 0 12px;
border: 0;
background: transparent;
font-family: var(--font-display);
font-size: 15px;
line-height: 1.25;
color: rgba(255, 255, 255, 0.66);
text-align: left;
@media (hover: hover) {
&:hover {
color: #fff;
}
}
&[aria-current="true"] {
color: var(--slash);
}
}
.ds-reel-chapter-num {
font-family: var(--font-mono);
font-size: 12px;
color: rgba(255, 255, 255, 0.5);
}
.ds-reel-chapter-pick[aria-current="true"] .ds-reel-chapter-num {
color: var(--slash);
}
@media (min-width: 1024px) {
.ds-reel-chapters {
display: grid;
}
}
@media (min-width: 1024px) and (pointer: coarse) {
.ds-reel-chapter-pick {
min-height: 44px;
}
}
.ds-reel-bar {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 2px;
background: var(--slash);
transform: scaleX(var(--p, 0));
transform-origin: left;
opacity: 0;
}
.ds-reel-pick[aria-current="true"] .ds-reel-bar {
opacity: 1;
}
@media (min-width: 640px) {
.ds-reel-name {
display: inline;
}
}
@media (min-width: 1024px) {
.ds-reel-hint {
display: flex;
}
.ds-reel-index > ol {
flex-direction: column;
gap: 6px;
overflow: visible;
}
.ds-reel-pick {
width: 100%;
gap: 14px;
padding: 0 16px;
}
}
.ds-reel-stage {
position: relative;
display: flex;
align-items: center;
justify-content: center;
min-height: 0;
/* o palco mede a si mesmo: o conjunto cresce até o limite da largura ou da altura que sobrar */
container-type: size;
}
/* aparelhos + legenda, um bloco só: a legenda tem sempre a mesma largura e o mesmo canto esquerdo do notebook */
.ds-reel-set {
--caption-h: 13.75rem; /* reserva da legenda: título, trecho atual e botões */
--gap: var(--sp-6);
display: flex;
flex-direction: column;
gap: var(--gap);
/* cabe na largura (com folga para o celular sobrepor) e na altura (legenda + barra de 30px + tela 16:10) */
width: min(90cqw, calc((100cqh - var(--caption-h) - var(--gap) - 30px) * 1.6));
min-width: min(100%, 320px);
}
/* as camadas de aparelhos (uma por projeto) ficam empilhadas na mesma célula: o bloco tem a altura de um par */
.ds-reel-devices {
position: relative;
display: grid;
}
.ds-reel-set {
isolation: isolate;
}
/* a troca de projeto é um fade cruzado só dos aparelhos (a legenda é um bloco à parte, abaixo): sem deslocamento.
Quem não está em cena já é inert (sem foco, sem clique, fora da busca) e aria-hidden. */
.ds-reel-layer {
--accent: var(--slash);
position: relative;
grid-area: 1 / 1;
min-width: 0;
opacity: 0;
pointer-events: none;
transition: opacity 0.45s ease;
&[data-state="active"] {
opacity: 1;
pointer-events: auto;
}
/* brilho na cor do site, atrás dos aparelhos */
&::before {
content: "";
position: absolute;
inset: -4% 0;
z-index: -1;
background: radial-gradient(
55% 60% at 50% 50%,
color-mix(in srgb, var(--accent) 42%, transparent),
transparent 72%
);
opacity: 0.45;
pointer-events: none;
}
}
.ds-reel-laptop {
width: 100%;
}
.ds-reel-screen {
position: relative;
aspect-ratio: 16 / 10;
overflow: hidden;
background: #0a0a0a center top / cover no-repeat;
& > video {
position: absolute;
inset: 0;
display: block;
width: 100%;
height: 100%;
object-fit: cover;
object-position: top;
}
}
.ds-reel-phone {
position: absolute;
right: -5%;
bottom: -3%;
width: 22%;
min-width: 88px;
}
.ds-reel-chapter {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 6px 12px;
margin-top: 4px;
font-size: 15px;
color: #fff;
& strong {
font-weight: 600;
}
}
.ds-reel-chapter-count {
font-family: var(--font-mono);
font-size: 12px;
letter-spacing: 0.06em;
color: var(--slash);
}
.ds-reel-ticks {
display: flex;
gap: 4px;
list-style: none;
& li {
width: 18px;
height: 3px;
background: rgba(255, 255, 255, 0.18);
transition: background 0.3s ease;
}
& li[data-state="done"] {
background: rgba(204, 255, 0, 0.5);
}
& li[data-state="now"] {
background: var(--slash);
}
}
/* desktop com pouca altura: a lista de projetos e os trechos têm de caber na altura do pin */
@media (min-width: 1024px) and (max-height: 700px) {
.ds-reel-hint {
display: none;
}
}
@media (min-width: 1024px) and (max-height: 700px) and (pointer: fine) {
.ds-reel-pick {
min-height: 38px;
}
.ds-reel-chapter-pick {
min-height: 28px;
}
}
/* janela curta: a reserva da legenda encolhe e o notebook ganha tela */
@media (min-width: 640px) and (max-height: 700px) {
.ds-reel-set {
--caption-h: 10.5rem;
}
}
/* Anel de foco do índice (sempre sobre fundo escuro): lima, por dentro, porque a faixa rolável e a lista de trechos
cortam o que passa da borda. Sem o halo do anel duplo global (globals.css): ele é para fundos claros. */
:is(.ds-reel-pick, .ds-reel-chapter-pick):focus-visible {
outline: 2px solid var(--slash);
outline-offset: -4px;
box-shadow: none;
}