portal_publico/static/css/aniversario-decor.css

233 lines
5.8 KiB
CSS

/* Bolo de aniversário do tema sazonal Aniversário (56 anos da De Paula
Contadores, só 15/10) — canto inferior-direito da tela Principal, com
velinhas que o usuário apaga clicando. Escondido por padrão (`hidden` no
HTML) e só exibido via `pidApplyAniversarioCake()` (seasonal-theme.js)
quando `pidIsAniversarioActive()` — ver
`docs/temas-sazonais/temas-sazonais.md`. */
.pid-aniv-cake {
position: fixed;
right: 20px;
bottom: 16px;
width: clamp(90px, 9vw, 130px);
z-index: 5;
pointer-events: none;
}
.pid-aniv-cake__btn {
all: unset;
display: block;
width: 100%;
cursor: pointer;
pointer-events: auto;
}
.pid-aniv-cake__btn svg {
display: block;
width: 100%;
height: auto;
overflow: visible;
filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.4));
}
.pid-cake-shadow {
fill: rgba(0, 0, 0, 0.3);
}
/* Cada gotejamento é da cor da camada DE CIMA (escorre sobre a de baixo) —
pintá-lo da mesma cor da própria camada o tornaria invisível. */
.pid-cake-tier2 {
fill: #7b5ba8;
}
.pid-cake-drip2 {
fill: #c6a24a;
}
.pid-cake-tier1 {
fill: #c6a24a;
}
.pid-cake-drip1 {
fill: #f2ede3;
}
.pid-cake-dot--blue {
fill: #2e86de;
}
.pid-cake-dot--pink {
fill: #e8446e;
}
.pid-cake-dot--amber {
fill: #f2a93b;
}
/* A luz das velas é feita em duas camadas: o `drop-shadow` aqui é o brilho
colado na própria chama (o "núcleo"), e `.pid-cake-halo` abaixo é o halo
largo de luz no ar em volta das velas. Os dois pulsam, mas em ciclos de
durações diferentes (1,4s e 2,6s) pra não parecerem sincronizados —
fogo real não pisca no compasso. O `filter` fica também na regra base (não
só nos keyframes) pra o brilho continuar existindo enquanto a chama se
apaga, quando `pidCakeFlameOut` assume o lugar do tremular. */
.pid-cake-flame {
fill: #f2a93b;
transform-box: fill-box;
transform-origin: center bottom;
filter: drop-shadow(0 0 2px rgba(242, 169, 59, 0.95)) drop-shadow(0 0 7px rgba(242, 169, 59, 0.5));
animation: pidCakeFlicker 1.4s ease-in-out infinite;
}
.pid-cake-halo {
/* Pico da intensidade — o tema claro abaixa (um brilho quente sobre fundo
claro vira névoa suja em vez de luz). */
--halo-max: 1;
transform-box: fill-box;
transform-origin: center;
animation: pidCakeHalo 2.6s ease-in-out infinite;
}
:root[data-theme="light"] .pid-cake-halo {
--halo-max: 0.5;
}
/* `nth-of-type` (não `nth-child`): as 3 velas são os 3 únicos `<g>` do SVG,
mas estão cercadas de `<path>`/`<circle>` do bolo, então a contagem por
posição absoluta não acertaria nenhuma delas. */
.pid-cake-candle:nth-of-type(2) .pid-cake-flame {
animation-delay: -0.5s;
}
.pid-cake-candle:nth-of-type(3) .pid-cake-flame {
animation-delay: -0.9s;
}
.pid-cake-smoke {
stroke: #b9aecb;
stroke-width: 1.1;
fill: none;
stroke-linecap: round;
opacity: 0;
/* Sem `fill-box`, o `scale` da fumaça subindo cresceria a partir da origem
do viewBox e jogaria o traço pra longe do pavio. */
transform-box: fill-box;
transform-origin: center bottom;
}
/* Clicar apaga as velinhas — toca uma vez (`pidApplyAniversarioCake()`,
seasonal-theme.js, adiciona `.is-blowing` no clique e troca pra `.is-blown`
`PID_CAKE_BLOW_MS` depois). `.is-blown` é o estado final em repouso (sem
`animation`), e dura só até o próximo carregamento da página: as velinhas
reacendem sozinhas, o estado apagado não é persistido de propósito (ver
`docs/temas-sazonais/temas-sazonais.md`). */
.pid-aniv-cake.is-blowing .pid-cake-flame {
animation: pidCakeFlameOut 500ms ease-out forwards;
}
.pid-aniv-cake.is-blowing .pid-cake-smoke {
animation: pidCakeSmokeRise 1400ms ease-out forwards;
}
.pid-aniv-cake.is-blowing .pid-cake-halo {
animation: pidCakeHaloOut 600ms ease-out forwards;
}
.pid-aniv-cake.is-blown .pid-cake-flame {
animation: none;
opacity: 0;
}
.pid-aniv-cake.is-blown .pid-cake-smoke {
animation: none;
opacity: 0;
}
.pid-aniv-cake.is-blown .pid-cake-halo {
animation: none;
opacity: 0;
}
.pid-aniv-cake.is-blowing .pid-aniv-cake__btn,
.pid-aniv-cake.is-blown .pid-aniv-cake__btn {
cursor: default;
pointer-events: none;
}
@keyframes pidCakeFlicker {
0%, 100% {
transform: scale(1) rotate(0deg);
opacity: 1;
filter: drop-shadow(0 0 2px rgba(242, 169, 59, 0.95)) drop-shadow(0 0 7px rgba(242, 169, 59, 0.5));
}
50% {
transform: scale(1.08) rotate(-3deg);
opacity: 0.9;
filter: drop-shadow(0 0 3px rgba(242, 169, 59, 1)) drop-shadow(0 0 11px rgba(242, 169, 59, 0.7));
}
}
@keyframes pidCakeHalo {
0%, 100% {
opacity: calc(var(--halo-max) * 0.72);
transform: scale(1);
}
50% {
opacity: var(--halo-max);
transform: scale(1.06);
}
}
@keyframes pidCakeFlameOut {
0% {
opacity: 1;
transform: scale(1) skewX(0deg);
filter: drop-shadow(0 0 3px rgba(242, 169, 59, 1)) drop-shadow(0 0 11px rgba(242, 169, 59, 0.7));
}
40% {
opacity: 0.6;
transform: scale(1.3) skewX(14deg);
filter: drop-shadow(0 0 2px rgba(242, 169, 59, 0.6)) drop-shadow(0 0 6px rgba(242, 169, 59, 0.3));
}
100% {
opacity: 0;
transform: scale(0.2) skewX(0deg);
filter: drop-shadow(0 0 0 rgba(242, 169, 59, 0));
}
}
/* A luz morre junto com a chama — um halo sobrevivendo às velas apagadas
deixaria uma mancha quente boiando no canto da tela. */
@keyframes pidCakeHaloOut {
0% {
opacity: calc(var(--halo-max) * 0.85);
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(0.82);
}
}
@keyframes pidCakeSmokeRise {
0% {
opacity: 0;
transform: translateY(0) scale(1);
}
15% {
opacity: 0.65;
}
100% {
opacity: 0;
transform: translateY(-14px) scale(1.7);
}
}
@media (max-width: 600px) {
.pid-aniv-cake {
width: clamp(72px, 20vw, 96px);
right: 12px;
bottom: 12px;
}
}