/* ---- Seasonal decorations: shared layer ------------------------------------
   Loaded only while a season is active (bin/php/seasonal/seasonal.php). Every
   rule here targets .vh-season* elements that a season adds; nothing restyles
   the page itself, so the client theme stays in charge underneath. Season art
   (bin/php/seasonal/<id>/season.css) positions its pieces inside these frames
   and colours them from the --vh-* theme tokens wherever it can. */

/* Zero-size sprite holder for the season's <symbol>s. Not display:none:
   gradients inside a display:none <svg> stop rendering in Chrome and Firefox. */
.vh-season-sprite {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

.vh-season,
.vh-season * {
    pointer-events: none;
    user-select: none;
}

/* Backdrop layer ('top' slot): from under the top bar down through the hero.
   It is emitted right after the backdrop video and before the page panels, so
   it paints over the backdrop and under every panel: decorations live in the
   scene around the UI and never cover text. Clipped, so nothing in it can add
   a horizontal scrollbar. */
.vh-season-backdrop {
    position: absolute;
    top: var(--vh-topbar-height);
    left: 0;
    width: 100%;
    height: 560px;
    overflow: hidden;
}

/* Sky ('top' slot, year seasons): the whole viewport behind the page panels,
   fixed like the backdrop image it sits on. Its background is the season's
   colour grade; its children are the weather. Contained and clipped, so
   nothing in it reaches layout or adds a scrollbar.
   - div children are fixed scenery (eaves, fronds);
   - span children are particles: they animate transform only (the compositor
     moves them, nothing repaints), phones show the first six, and they are
     removed under prefers-reduced-motion. */
.vh-season-sky {
    position: fixed;
    inset: 0;
    overflow: hidden;
    contain: strict;
}

.vh-season-sky > span {
    position: absolute;
    top: 0;
    left: var(--x, 50%);
}

/* Eaves: a strip hanging from the top bar's bottom edge. The masks cut two
   interleaved rows of icicles (different tile widths, so the row never looks
   repeated); a season paints it and sets --eaves to the longest icicle. */
.vh-season-eaves {
    position: absolute;
    top: var(--vh-topbar-height);
    left: 0;
    width: 100%;
    height: var(--eaves, 24px);
    -webkit-mask: var(--vh-season-icicles-a) 0 0 / 140px 100% repeat-x, var(--vh-season-icicles-b) 31px 0 / 97px 75% repeat-x;
    mask: var(--vh-season-icicles-a) 0 0 / 140px 100% repeat-x, var(--vh-season-icicles-b) 31px 0 / 97px 75% repeat-x;
}

/* Shared piece defaults (a holiday overrides them on .vh-season--<id>):
   candle wax and flame colours, and the two icicle rows the eaves cut. */
.vh-season {
    --wax: var(--vh-text);
    --glow: var(--vh-option);
    --glow-core: #fffbe2;
    --vh-season-icicles-a: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 140 24' preserveAspectRatio='none'%3E%3Cpath d='M0 0H140V3H0ZM5 2L8 15L11 2ZM19 2L21 9L23 2ZM32 2L36 24L40 2ZM51 2L53.5 11L56 2ZM65 2L68.5 17L72 2ZM84 2L86 8L88 2ZM96 2L100.5 22L105 2ZM117 2L119.5 12L122 2ZM130 2L133 10L136 2Z'/%3E%3C/svg%3E");
    --vh-season-icicles-b: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 97 24' preserveAspectRatio='none'%3E%3Cpath d='M12 0L15 14L18 0ZM43 0L45 8L47 0ZM70 0L73.5 19L77 0Z'/%3E%3C/svg%3E");
}

/* Nook ('footer' slot): the empty bottom-right corner inside the footer links
   panel, under its short Agreements list. Out of flow, so the panel keeps its size. */
.vh-season-nook {
    position: absolute;
    right: 22px;
    bottom: 14px;
    display: flex;
    align-items: flex-end;
    gap: 4px;
    transform-origin: 100% 100%;
}

/* Ledge ('nav' slot): a zero-height line on the navigation panel's top edge.
   Pieces stand on the line at either end and never change the layout. */
.vh-season-ledge {
    position: relative;
    height: 0;
}

.vh-season-ledge__end {
    position: absolute;
    bottom: 0;
    display: flex;
    align-items: flex-end;
    gap: 4px;
}

.vh-season-ledge__end--left {
    left: 14px;
    transform-origin: 0 100%;
}

.vh-season-ledge__end--right {
    right: 14px;
    transform-origin: 100% 100%;
}

.vh-season svg {
    display: block;
    overflow: visible;
}

/* ---- Shared pieces ------------------------------------------------------------
   The mechanics every holiday reuses, so a set only supplies its art and
   colours. Each piece reads custom properties that the holiday sets on its own
   classes (defaults in brackets). */

/* Corner (top slot): art anchored in a top corner of the backdrop, mirrored on
   the right. --corner is its size; holidays let it grow with wide screens. */
.vh-season-corner {
    position: absolute;
    top: 0;
    width: var(--corner);
    height: var(--corner);
}

.vh-season-corner--left { left: 0; }

.vh-season-corner--right {
    right: 0;
    transform: scaleX(-1);
}

/* Dangle (top slot): a piece on a thread from under the top bar. The column
   (--size wide) sways from its anchor every --sway (5s). Its drop rests at
   --rest and lowers to --drop and back every --cycle, starting --delay into
   it; a --still dangle only sways. The thread (--thread colour, --thread-width
   1px) runs up out of the clipped backdrop. The content brings its own size
   and motion. */
.vh-season-dangle {
    position: absolute;
    top: 0;
    width: var(--size, 30px);
    transform-origin: 50% 0;
    animation: vh-season-sway var(--sway, 5s) ease-in-out infinite alternate;
}

.vh-season-dangle__drop {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    transform: translateY(var(--rest, 0px));
    animation: vh-season-descend var(--cycle, 15s) ease-in-out var(--delay, 0s) infinite;
}

.vh-season-dangle--still .vh-season-dangle__drop {
    animation: none;
}

.vh-season-dangle__drop::before {
    content: "";
    position: absolute;
    bottom: 100%;
    left: 50%;
    width: var(--thread-width, 1px);
    height: 600px;
    margin-left: calc(var(--thread-width, 1px) / -2);
    background: var(--thread, var(--vh-muted));
    opacity: var(--thread-opacity, 0.6);
}

/* Flyer (top slot): crosses the hero from off-screen left on a gentle wave at
   height --y, once every --cycle, starting --delay into it. A flyer wider than
   70px moves its own left edge out and sets --overshoot to its width, so it
   both starts and parks fully off-screen. */
.vh-season-flyer {
    position: absolute;
    left: -70px;
    top: var(--y, 80px);
    animation: vh-season-flight var(--cycle, 24s) ease-in-out var(--delay, 0s) infinite;
}

/* Candle (ledge and nook): --wax body with a drip and a wick, --candle tall,
   lit by a flame. The flame is a rounded teardrop from --glow-core through the
   theme's hint text to --glow, with a soft --glow halo. */
.vh-season-candle {
    position: relative;
    display: block;
    width: 9px;
    height: var(--candle, 26px);
    margin: 0 2px;
    border-radius: 3px 3px 1px 1px / 2px 2px 1px 1px;
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--wax) 62%, #000000) 0%,
        var(--wax) 35%,
        color-mix(in srgb, var(--wax) 55%, #ffffff) 55%,
        var(--wax) 72%,
        color-mix(in srgb, var(--wax) 62%, #000000) 100%);
    box-shadow: inset 0 -4px 5px rgba(0, 0, 0, 0.35);
}

.vh-season-candle--tall { --candle: 38px; }
.vh-season-candle--short { --candle: 17px; }

.vh-season-candle::before {
    content: "";
    position: absolute;
    top: 0;
    left: 1px;
    width: 3px;
    height: 8px;
    border-radius: 0 0 2px 2px;
    background: var(--wax);
}

.vh-season-candle::after {
    content: "";
    position: absolute;
    top: -4px;
    left: 50%;
    width: 1.5px;
    height: 5px;
    margin-left: -0.75px;
    border-radius: 1px;
    background: #2a201a;
}

.vh-season-flame {
    position: absolute;
    bottom: calc(100% + 1px);
    left: 50%;
    width: 8px;
    height: 14px;
    margin-left: -4px;
    transform-origin: 50% 100%;
    animation: vh-season-flicker 1.5s ease-in-out infinite;
}

.vh-season-flame::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50% 50% 50% 50% / 68% 68% 32% 32%;
    background: radial-gradient(ellipse 60% 55% at 50% 72%, var(--glow-core) 0 30%, var(--vh-hint-text) 45%, var(--glow) 75%, color-mix(in srgb, var(--glow) 0%, transparent) 100%);
}

.vh-season-flame::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 55%;
    width: 46px;
    height: 46px;
    margin: -23px 0 0 -23px;
    border-radius: 50%;
    background: radial-gradient(closest-side, color-mix(in srgb, var(--glow) 30%, transparent), transparent);
    animation: vh-season-glow 1.9s ease-in-out infinite;
}

.vh-season-candle:nth-child(2n) .vh-season-flame { animation-duration: 1.2s; animation-delay: -0.5s; }
.vh-season-candle:nth-child(3n) .vh-season-flame { animation-duration: 1.8s; animation-delay: -0.9s; }

/* Shared motion: vh-season-glow pulses a halo's opacity, vh-season-float
   bobs a piece in place. */
@keyframes vh-season-sway {
    from { transform: rotate(-2.5deg); }
    to { transform: rotate(2.5deg); }
}

@keyframes vh-season-descend {
    0%, 100% { transform: translateY(var(--rest, 0px)); }
    42%, 64% { transform: translateY(var(--drop, 0px)); }
}

@keyframes vh-season-flight {
    0% { transform: translate(0, 0); }
    10% { transform: translate(25vw, -26px); }
    20% { transform: translate(50vw, 12px); }
    30% { transform: translate(75vw, -20px); }
    40%, 100% { transform: translate(calc(100vw + 140px + var(--overshoot, 0px)), 6px); }
}

@keyframes vh-season-flicker {
    0%, 100% { transform: scale(1, 1) skewX(0deg); }
    20% { transform: scale(0.92, 1.08) skewX(-4deg); }
    40% { transform: scale(1.05, 0.94) skewX(2deg); }
    60% { transform: scale(0.96, 1.05) skewX(-1deg); }
    80% { transform: scale(1.02, 0.97) skewX(3deg); }
}

@keyframes vh-season-glow {
    0%, 100% { opacity: 0.85; }
    30% { opacity: 0.6; }
    50% { opacity: 1; }
    70% { opacity: 0.7; }
}

@keyframes vh-season-float {
    0%, 100% { transform: translateY(0) rotate(-2deg); }
    50% { transform: translateY(-8px) rotate(2deg); }
}

/* Narrower desktops: smaller pieces so the ends stay clear of Play Now. */
@media (max-width: 1100px) {
    .vh-season-ledge__end,
    .vh-season-nook {
        transform: scale(0.8);
    }
}

/* Phones: the navigation panel is folded behind the Menu button. */
@media (max-width: 767px) {
    .vh-season-backdrop {
        height: 420px;
    }

    .vh-season-ledge--nav {
        display: none;
    }

    .vh-season-nook {
        right: 12px;
        bottom: 10px;
        transform: scale(0.7);
    }

    .vh-season-sky > span:nth-of-type(n+7) {
        display: none;
    }

    .vh-season-eaves {
        height: calc(var(--eaves, 24px) * 0.7);
    }
}

@media (prefers-reduced-motion: reduce) {
    .vh-season-sky > span {
        display: none;
    }

    .vh-season *,
    .vh-season *::before,
    .vh-season *::after {
        animation: none !important;
    }
}

@media print {
    .vh-season {
        display: none !important;
    }
}
