/* Safety net: nothing on this page should ever need horizontal scroll, so
   if any element (now or added later) is ever a hair too wide for the
   viewport, this keeps it from becoming a scrollable/interactive overflow
   instead of just being invisible past the edge. */
html {
    overflow-x: hidden;
}

/* Volume slider -- a plain <input type="range"> renders with a thin,
   easy-to-miss native track/thumb by default in every browser, which is
   exactly what made it hard to notice or grab precisely (especially by
   touch) before this existed. Chrome/Safari/Edge (WebKit/Blink) and
   Firefox each need their own vendor-prefixed pseudo-elements -- there's
   no single standard one that covers all of them -- so the same visual
   intent (a solid rounded 8px track, an 18px round thumb) necessarily
   gets stated twice rather than once. Colors are the literal hex values
   behind Tailwind's gray-700/gray-800/blue-500, kept in sync with
   accent-blue-500 already on the element in index.php (that utility
   class stays as a harmless fallback for whatever a browser might still
   render natively outside what's explicitly styled below).
*/
#masterVolumeSlider {
    height: 20px; /* a taller hit area than the 8px track itself, so a tap/click anywhere in this vertical space still lands on the slider */
    cursor: pointer;
}

#masterVolumeSlider::-webkit-slider-runnable-track {
    height: 8px;
    border-radius: 9999px;
    background: #374151; /* gray-700 */
}
#masterVolumeSlider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 18px;
    height: 18px;
    border-radius: 9999px;
    background: #3b82f6; /* blue-500 */
    border: 2px solid #1f2937; /* gray-800 -- separates the thumb from the track fill sitting right behind it */
    margin-top: -5px; /* (8px track - 18px thumb) / 2, centers the thumb vertically on the track */
}

#masterVolumeSlider::-moz-range-track {
    height: 8px;
    border-radius: 9999px;
    background: #374151;
}
#masterVolumeSlider::-moz-range-thumb {
    width: 18px;
    height: 18px;
    border-radius: 9999px;
    background: #3b82f6;
    border: 2px solid #1f2937;
}


body::before {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    /* 100% (not 100vw/100vh): for a fixed-position element, percentages
       resolve against the viewport directly, while vw/vh units are
       defined to include the width a scrollbar would occupy -- meaning
       this layer could render slightly WIDER than the visible page,
       causing horizontal overflow. That's a known, common cause of a
       page technically being able to scroll a couple of stray pixels even
       though nothing looks like it should require scrolling at all. */
    width: 100%;
    height: 100%;
    /* No picture here: each streamer's own background art comes from the streamers table (bg_image, or img/{slug}_bg.jpg)
       and is written into <head> by index.php as a body.streamer-{slug}::before rule. A streamer with no background file
       simply has none, instead of quietly borrowing someone else's. */
    background: no-repeat center center;
    background-size: contain;
    opacity: 0.2; /* Fades the image out */
    mix-blend-mode: screen; /* Drops the black pixels, keeps the light text */
    filter: blur(2px); /* Softens the text so it isn't distracting */
    pointer-events: none; /* Ensures the background doesn't block mouse clicks */
    z-index: -1; /* Keeps it behind all your UI elements */
}

/* Per-streamer background art is not defined in this file any more. index.php writes one
   body.streamer-{slug}::before { background-image: url(...) } rule per streamer into <head>, from that streamer's bg_image
   column (see streamerBackgroundCss() in includes/clip-catalog.php), so adding a streamer's background is a database row
   plus a file, not an edit here. The soft streamer switch in app.js only swaps the body's streamer-{slug} class, and
   these rules follow that class, so nothing else is involved. (This used to be the generic bg.png above plus a rule each
   for Bean and NikTheVoker; every other streamer fell through to Chuck's bg.png.) */

/* Continuous Reel Spin Animation */
.reel-strip {
    display: flex;
    flex-direction: column;
    animation: spinReel linear infinite;
    will-change: transform;
}

/* Idle State: Slow ambient scroll */
.slow-spin { 
    animation-duration: 25s; 
}

/* Action State: High-speed spin with motion blur */
.fast-spin { 
    animation-duration: 0.6s; 
    filter: blur(3px) drop-shadow(0 0 10px rgba(255,255,255,0.1)); 
}

@keyframes spinReel {
    0% { transform: translateY(0); }
    100% { transform: translateY(-50%); } 
}

/* Staggered reel start delays to make the spin look organic */
#reelsContainer > div:nth-child(1) .reel-strip { animation-delay: 0s; }
#reelsContainer > div:nth-child(2) .reel-strip { animation-delay: -5s; }
#reelsContainer > div:nth-child(3) .reel-strip { animation-delay: -12s; }
#reelsContainer > div:nth-child(4) .reel-strip { animation-delay: -18s; }
#reelsContainer > div:nth-child(5) .reel-strip { animation-delay: -2s; }

/* Featured Slot badge: pops in large the instant a clip starts, holds
   briefly so it actually registers, then eases back down into its small
   resting size -- and separately, hovering it manually does the exact
   same enlarge, at any time, even mid-pop. Both share ONE mechanism (a
   plain CSS transition on transform, not a keyframe animation) so they
   can never conflict: a keyframe animation with fill-mode:forwards would
   keep holding the transform property for as long as its class stayed
   applied, blocking a hover transition on the same property from taking
   over until it was removed -- exactly what caused hover to do nothing
   until the pop had fully finished shrinking. See pulseFeaturedSlotBadge()
   in app.js, which toggles .featured-badge-enlarged on a timer rather
   than an animation class. transform-origin: top right matches the
   badge's own docked position (absolute top-1 right-3) so enlarging
   always grows down-and-left INTO that corner, whichever of the two
   triggers it. cursor: zoom-in signals what hovering actually does here,
   since this isn't a clickable link/button. */
#featuredSlotContainer {
    transform-origin: top right;
    transition: transform 0.25s ease;
    cursor: pointer;
}
#featuredSlotContainer:hover,
#featuredSlotContainer.featured-badge-enlarged {
    transform: scale(1.7); /* was 2: the enlarged badge now sits inside the header strip above the video instead of spilling past it. The one number to change if it needs to be a touch bigger or smaller. */
}

/* Mechanical Slide-In States */
.result-hidden {
    transform: translateY(-100%);
}
.result-visible {
    transform: translateY(0);
}

.glow-safe { filter: drop-shadow(0 0 20px rgba(34, 197, 94, 0.6)); }
.glow-slot { filter: drop-shadow(0 0 20px rgba(239, 68, 68, 0.6)); }
.glow-provider { filter: drop-shadow(0 0 20px rgba(6, 182, 212, 0.6)); }
.glow-people { filter: drop-shadow(0 0 20px rgba(168, 85, 247, 0.6)); }
.glow-food { filter: drop-shadow(0 0 20px rgba(236, 72, 153, 0.6)); }

/* Shown on the same status bar a real clip's SLOT BANNED/PROVIDER BANNED/
   etc header uses, now that a commercial plays through that exact same
   element too (see playVideoInMainElement()/playCommercialSrc() in
   app.js) -- matches the yellow accent the old standalone Commercial
   Break corner badge used to use, kept for visual continuity. */
.glow-commercial { filter: drop-shadow(0 0 20px rgba(234, 179, 8, 0.6)); }

/* Wins-mode equivalents (gold/blue/green/teal instead of red/orange/purple/pink) */
.glow-slot-win { filter: drop-shadow(0 0 20px rgba(234, 179, 8, 0.6)); }
.glow-provider-win { filter: drop-shadow(0 0 20px rgba(59, 130, 246, 0.6)); }
.glow-people-win { filter: drop-shadow(0 0 20px rgba(34, 197, 94, 0.6)); }
.glow-food-win { filter: drop-shadow(0 0 20px rgba(20, 184, 166, 0.6)); }

/* For a slot confirmed to match BOTH a ban rule and a win rule (see
   findOppositeClipTypeMatch()/getRainbowTheme() in app.js) -- a single
   flat drop-shadow color can't itself look like a rainbow the way
   RAINBOW_GRADIENT_CLASS's bg-[...] bar/text can, so this cycles hue
   through the same six stops instead, continuously. */
.glow-rainbow {
    animation: rainbow-glow-cycle 3s linear infinite;
}
@keyframes rainbow-glow-cycle {
    0%   { filter: drop-shadow(0 0 20px rgba(239, 68, 68, 0.6)); }
    16%  { filter: drop-shadow(0 0 20px rgba(249, 115, 22, 0.6)); }
    33%  { filter: drop-shadow(0 0 20px rgba(234, 179, 8, 0.6)); }
    50%  { filter: drop-shadow(0 0 20px rgba(34, 197, 94, 0.6)); }
    66%  { filter: drop-shadow(0 0 20px rgba(59, 130, 246, 0.6)); }
    83%  { filter: drop-shadow(0 0 20px rgba(139, 92, 246, 0.6)); }
    100% { filter: drop-shadow(0 0 20px rgba(239, 68, 68, 0.6)); }
}

/* Brief "glitch" flash when switching between Chuck/Bean modes -- see
   setMode() in app.js, which just adds this class for ~450ms and lets
   these keyframes do the rest. Combines a quick jitter, a color/filter
   flicker, an RGB-split flash on the title, and a scanline sweep -- pure
   CSS, no content duplicated or touched, so this is safe to trigger on
   every mode switch without any performance cost. steps(2, end) on the
   jitter/filter animations (rather than the default smooth easing) is
   what gives them a jumpy, glitchy feel instead of a smooth wobble. */
@keyframes glitch-jitter {
    0%   { transform: translate(0, 0); }
    10%  { transform: translate(-4px, 2px); }
    20%  { transform: translate(3px, -2px); }
    30%  { transform: translate(-2px, 0); }
    40%  { transform: translate(2px, 3px); }
    50%  { transform: translate(-3px, -1px); }
    60%  { transform: translate(4px, 1px); }
    70%  { transform: translate(-2px, -2px); }
    80%  { transform: translate(1px, 2px); }
    90%  { transform: translate(-1px, 0); }
    100% { transform: translate(0, 0); }
}

@keyframes glitch-filter {
    0%   { filter: hue-rotate(0deg) contrast(1) brightness(1) saturate(1); }
    15%  { filter: hue-rotate(90deg) contrast(1.5) brightness(1.3) saturate(2); }
    30%  { filter: hue-rotate(-60deg) contrast(0.8) brightness(0.8) saturate(1.5); }
    45%  { filter: hue-rotate(180deg) contrast(1.8) brightness(1.5) saturate(2.5); }
    60%  { filter: hue-rotate(-30deg) contrast(1.2) brightness(1) saturate(1.5); }
    75%  { filter: hue-rotate(45deg) contrast(1.4) brightness(1.1) saturate(1.2); }
    100% { filter: hue-rotate(0deg) contrast(1) brightness(1) saturate(1); }
}

@keyframes glitch-text-split {
    0%   { text-shadow: none; }
    20%  { text-shadow: 2px 0 red, -2px 0 cyan; }
    40%  { text-shadow: -3px 0 red, 3px 0 cyan; }
    60%  { text-shadow: 2px 0 red, -2px 0 cyan; }
    80%  { text-shadow: -1px 0 red, 1px 0 cyan; }
    100% { text-shadow: none; }
}

@keyframes glitch-scanline-fade {
    0%   { opacity: 0.7; }
    100% { opacity: 0; }
}

body.mode-glitching #siteTitle {
    animation: glitch-text-split 0.45s steps(2, end);
}

/* Applied to the whole page's own visual output via the body itself, not
   a wrapper -- everything currently on screen flickers together, which
   is the point (a mode switch is about to change nearly all of it
   anyway: colors, title, badges, background). */
body.mode-glitching {
    animation-name: glitch-jitter, glitch-filter;
    animation-duration: 0.45s, 0.45s;
    animation-timing-function: steps(2, end), steps(2, end);
}

/* Thin animated scanline sweep on top of everything -- a fixed overlay so
   it isn't affected by the jitter/filter animations above (which apply to
   body's own rendering, not to a pseudo-element layered above it). */
body.mode-glitching::after {
    content: '';
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 9999;
    background: repeating-linear-gradient(
        0deg,
        rgba(255, 255, 255, 0.06) 0px,
        rgba(255, 255, 255, 0.06) 1px,
        transparent 1px,
        transparent 3px
    );
    mix-blend-mode: overlay;
    animation: glitch-scanline-fade 0.45s ease-out forwards;
}

/* Custom Scrollbar for Autocomplete */
::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-track { background: #1f2937; }
::-webkit-scrollbar-thumb { background: #4b5563; border-radius: 4px; }

/* Top Clips marquee -- #topClipsList is rendered with its card set
   duplicated back-to-back (see renderTopClips() in app.js), so sliding
   exactly -50% loops seamlessly back to the same visual starting point
   with no jump or gap. Runs continuously regardless of the mouse --
   deliberately not paused on hover, so it keeps moving even while
   someone's cursor is resting over the section. */
@keyframes topclips-scroll {
    from { transform: translateX(0); }
    to { transform: translateX(-50%); }
}
#topClipsList.animate-marquee {
    animation: topclips-scroll 55s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
    #topClipsList.animate-marquee {
        animation: none;
    }
}

/* Soft fade at both edges of the marquee's viewport, rather than a hard
   clip -- cards slide out of view gradually instead of vanishing at a
   sharp boundary. Purely cosmetic, applied to the OUTER section
   (topClipsSection) so it masks the whole visible strip regardless of
   where the inner track has scrolled to. */
.topclips-fade {
    -webkit-mask-image: linear-gradient(to right, transparent 0, black 24px, black calc(100% - 24px), transparent 100%);
    mask-image: linear-gradient(to right, transparent 0, black 24px, black calc(100% - 24px), transparent 100%);
}
::-webkit-scrollbar-thumb:hover { background: #6b7280; }