/* 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 `` do SVG, mas estão cercadas de ``/`` 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; } }