/* tw-fade - CSS scroll-edge fade masking for Tailwind v4. MIT - github.com/petekp/tw-fade */

/* Amounts: keep <number> so scroll animation interpolates them; initial 0 = no fade. */
@property --tw-fade-t {
    syntax: "<number>";
    inherits: false;
    initial-value: 0;
}
@property --tw-fade-b {
    syntax: "<number>";
    inherits: false;
    initial-value: 0;
}
@property --tw-fade-l {
    syntax: "<number>";
    inherits: false;
    initial-value: 0;
}
@property --tw-fade-r {
    syntax: "<number>";
    inherits: false;
    initial-value: 0;
}

/*
Config: keep "*" with NO initial-value. A typed <length> rejects the rem
fallback and drops the registration in browsers; inherits:false stops nested
fades from leaking size, travel, clearance, mask, or routing state.
*/
@property --tw-fade-size {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-size-y {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-size-x {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-size-top {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-size-bottom {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-size-start {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-size-end {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-travel {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-clear {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-clear-y {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-clear-x {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-clear-top {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-clear-bottom {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-clear-start {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-clear-end {
    syntax: "*";
    inherits: false;
}
/*
Opt-in scrollbar protection. Width of the opaque mask strip that shields a
space-consuming (classic) scrollbar's inline-end column from the fade. Default
0px = inert (no extra coverage), so base fades are byte-for-byte unchanged.
fade-scrollbar-safe-y / -xy set it; users may also set --tw-fade-scrollbar directly.

Typed <length>, unlike the "*" properties above, because this one is substituted
into mask-size -- and a single bad component makes the WHOLE declaration invalid
at computed-value time, so all six layers fall back to `auto`, which on a
gradient means the full positioning area. An opaque layer then covers the entire
element and the fade vanishes. A typed property with an initial value can't do
that: a value that doesn't parse as a <length> (`11` instead of `11px`) is
dropped at computed-value time and, with inherits:false, the property falls back
to its initial value. So the failure mode of a typo is an inert strip rather
than a silently disabled plugin.
*/
@property --tw-fade-scrollbar {
    syntax: "<length>";
    inherits: false;
    initial-value: 0px;
}
/*
Block-axis counterpart, for the horizontal bar along the block end. Separate
from --tw-fade-scrollbar and separately opt-in because the two gutters are NOT
equally knowable. scrollbar-gutter:stable reserves the inline gutter whether or
not the box currently overflows, so the inline strip is safe to apply blind.
It reserves nothing on the block axis: measured across Chromium and WebKit, the
block gutter is 0 unless content actually overflows horizontally, and no
scrollbar-gutter value changes that. A blind block strip would therefore paint
an opaque band over real CONTENT on every vertical-only scroller.

CSS cannot detect horizontal overflow, but the author knows. So this stays 0
until fade-scrollbar-safe-x / -xy (or a direct declaration) assert it -- the same
move as pinning the width: declare the one bit that cannot be derived.
*/
@property --tw-fade-scrollbar-block {
    syntax: "<length>";
    inherits: false;
    initial-value: 0px;
}
/*
Public knob for the pinned bar size. Registered rather than left as a bare
custom property so a malformed value degrades to the initial value instead of
reaching ::-webkit-scrollbar { width: <garbage> } -- which would drop that
declaration, un-pin the bar, and leave the strip shielding a column of the
wrong width.

<length> still admits negative values. That is harmless for the property itself
but invalid in mask-size, where one negative layer invalidates the whole six-layer
declaration and silently removes the fade. Every consumption therefore clamps
the public value with max(0px, ...) -- the bar and both strips all read the same
sanitized length, so a negative arbitrary utility, theme token, or direct value
degrades to an inert 0px bar/strip instead.

inherits:true is REQUIRED here, unlike every other property in this file.
::-webkit-scrollbar is a pseudo-element, and pseudo-elements only see a custom
property through inheritance from their originating element. Registered with
inherits:false the pin silently reads the INITIAL value instead of the author's:
measured, declaring 24px produced an 11px bar in both Chromium and WebKit while
the strip -- read from the element itself, where the declaration is visible --
correctly became 24px. That is a 13px opaque slab over content, which is exactly
the misalignment the pin exists to make impossible.

Inheriting is also what makes fade-scrollbar-width-* useful on an ancestor --
set it once on <body> and every opted-in scroller below picks it up. The cost of
that reach is real and worth stating: a nested scroller that has opted in gets
retuned by an ancestor's setting, since it inherits the value like any other
custom property. It is inert on elements that never read it (no fade-scrollbar
utility => no pin, no strip), so the blast radius is "scrollers you already
opted in", not "the whole page". Override it on the nested scroller to opt out.

15px matches the macOS classic bar. The pin REPLACES the native bar rather than
decorating it, so this value is the actual hit target the user gets; defaulting
below native trades pointer accuracy for looks, which is not a default's call.
*/
@property --tw-fade-scrollbar-width {
    syntax: "<length>";
    inherits: true;
    initial-value: 15px;
}
@property --tw-fade-mask-t {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-mask-b {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-mask-l {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-mask-r {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-ltr-start-layer {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-ltr-end-layer {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-rtl-start-layer {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-rtl-end-layer {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-ltr-start-animation {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-ltr-end-animation {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-rtl-start-animation {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-rtl-end-animation {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-ltr-start-timeline {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-ltr-end-timeline {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-rtl-start-timeline {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-rtl-end-timeline {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-ltr-start-animation-range {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-ltr-end-animation-range {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-rtl-start-animation-range {
    syntax: "*";
    inherits: false;
}
@property --tw-fade-rtl-end-animation-range {
    syntax: "*";
    inherits: false;
}

@theme {
    --fade-size-xs: calc(var(--spacing, 0.25rem) * 6);
    --fade-size-sm: calc(var(--spacing, 0.25rem) * 8);
    --fade-size-md: calc(var(--spacing, 0.25rem) * 12);
    --fade-size-lg: calc(var(--spacing, 0.25rem) * 16);
    --fade-size-xl: calc(var(--spacing, 0.25rem) * 20);
    --fade-size-2xl: calc(var(--spacing, 0.25rem) * 24);
    --fade-size-3xl: calc(var(--spacing, 0.25rem) * 32);
    --fade-size-4xl: calc(var(--spacing, 0.25rem) * 40);
    --fade-travel-xs: calc(var(--spacing, 0.25rem) * 6);
    --fade-travel-sm: calc(var(--spacing, 0.25rem) * 8);
    --fade-travel-md: calc(var(--spacing, 0.25rem) * 12);
    --fade-travel-lg: calc(var(--spacing, 0.25rem) * 16);
    --fade-travel-xl: calc(var(--spacing, 0.25rem) * 20);
    --fade-travel-2xl: calc(var(--spacing, 0.25rem) * 24);
    --fade-travel-3xl: calc(var(--spacing, 0.25rem) * 32);
    --fade-travel-4xl: calc(var(--spacing, 0.25rem) * 40);
    --fade-clear-xs: calc(var(--spacing, 0.25rem) * 6);
    --fade-clear-sm: calc(var(--spacing, 0.25rem) * 8);
    --fade-clear-md: calc(var(--spacing, 0.25rem) * 12);
    --fade-clear-lg: calc(var(--spacing, 0.25rem) * 16);
    --fade-clear-xl: calc(var(--spacing, 0.25rem) * 20);
    --fade-clear-2xl: calc(var(--spacing, 0.25rem) * 24);
    --fade-clear-3xl: calc(var(--spacing, 0.25rem) * 32);
    --fade-clear-4xl: calc(var(--spacing, 0.25rem) * 40);
    /*
    Absolute px, not the spacing ramp the scales above use: a scrollbar is device
    chrome, not typographic rhythm, and it should not resize with the root font.
    Three steps, each a real native bar width, because there are only about three
    defensible widths for a scrollbar.

    Deliberately NOT named thin / auto / none. Those are the literal keywords of
    the real scrollbar-width property -- which this plugin must never set, since
    setting it makes Blink discard ::-webkit-scrollbar and cancels the pin. A
    token named `thin` would read like that property and do something else.
    Unmatched suffixes emit nothing, so fade-scrollbar-width-thin is inert.
    */
    --fade-scrollbar-width-sm: 11px; /* slim, below native, for dense chrome */
    --fade-scrollbar-width-md: 15px; /* the default; macOS classic          */
    --fade-scrollbar-width-lg: 17px; /* Windows classic / Fluent            */
}

@keyframes tw-fade-travel-t {
    from {
        --tw-fade-t: 0;
    }
    to {
        --tw-fade-t: 1;
    }
}
@keyframes tw-fade-travel-b {
    from {
        --tw-fade-b: 1;
    }
    to {
        --tw-fade-b: 0;
    }
}
@keyframes tw-fade-travel-l {
    from {
        --tw-fade-l: 0;
    }
    to {
        --tw-fade-l: 1;
    }
}
@keyframes tw-fade-travel-r {
    from {
        --tw-fade-r: 1;
    }
    to {
        --tw-fade-r: 0;
    }
}
@keyframes tw-fade-travel-r-leading {
    from {
        --tw-fade-r: 0;
    }
    to {
        --tw-fade-r: 1;
    }
}
@keyframes tw-fade-travel-l-trailing {
    from {
        --tw-fade-l: 1;
    }
    to {
        --tw-fade-l: 0;
    }
}

@utility fade-size-* {
    --tw-fade-size: --value(--fade-size-*, [length], [percentage]);
}
@utility fade-size-y-* {
    --tw-fade-size-y: --value(--fade-size-*, [length], [percentage]);
}
@utility fade-size-x-* {
    --tw-fade-size-x: --value(--fade-size-*, [length], [percentage]);
}
@utility fade-size-top-* {
    --tw-fade-size-top: --value(--fade-size-*, [length], [percentage]);
}
@utility fade-size-bottom-* {
    --tw-fade-size-bottom: --value(--fade-size-*, [length], [percentage]);
}
@utility fade-size-start-* {
    --tw-fade-size-start: --value(--fade-size-*, [length], [percentage]);
}
@utility fade-size-end-* {
    --tw-fade-size-end: --value(--fade-size-*, [length], [percentage]);
}
@utility fade-travel-* {
    --tw-fade-travel: --value(--fade-travel-*, [length], [percentage]);
}
@utility fade-clear-* {
    --tw-fade-clear: calc(var(--spacing, 0.25rem) * --value(integer));
    --tw-fade-clear: --value(--fade-clear-*, [length], [percentage]);
}
@utility fade-clear-y-* {
    --tw-fade-clear-y: calc(var(--spacing, 0.25rem) * --value(integer));
    --tw-fade-clear-y: --value(--fade-clear-*, [length], [percentage]);
}
@utility fade-clear-x-* {
    --tw-fade-clear-x: calc(var(--spacing, 0.25rem) * --value(integer));
    --tw-fade-clear-x: --value(--fade-clear-*, [length], [percentage]);
}
@utility fade-clear-top-* {
    --tw-fade-clear-top: calc(var(--spacing, 0.25rem) * --value(integer));
    --tw-fade-clear-top: --value(--fade-clear-*, [length], [percentage]);
}
@utility fade-clear-bottom-* {
    --tw-fade-clear-bottom: calc(var(--spacing, 0.25rem) * --value(integer));
    --tw-fade-clear-bottom: --value(--fade-clear-*, [length], [percentage]);
}
@utility fade-clear-start-* {
    --tw-fade-clear-start: calc(var(--spacing, 0.25rem) * --value(integer));
    --tw-fade-clear-start: --value(--fade-clear-*, [length], [percentage]);
}
@utility fade-clear-end-* {
    --tw-fade-clear-end: calc(var(--spacing, 0.25rem) * --value(integer));
    --tw-fade-clear-end: --value(--fade-clear-*, [length], [percentage]);
}
@utility fade-clear-var {
    --tw-fade-clear: var(--fade-clear, 0px);
}
@utility fade-clear-y-var {
    --tw-fade-clear-y: var(--fade-clear-y, var(--fade-clear, 0px));
}
@utility fade-clear-x-var {
    --tw-fade-clear-x: var(--fade-clear-x, var(--fade-clear, 0px));
}
@utility fade-clear-top-var {
    --tw-fade-clear-top: var(--fade-clear-top, var(--fade-clear-y, var(--fade-clear, 0px)));
}
@utility fade-clear-bottom-var {
    --tw-fade-clear-bottom: var(--fade-clear-bottom, var(--fade-clear-y, var(--fade-clear, 0px)));
}
@utility fade-clear-start-var {
    --tw-fade-clear-start: var(--fade-clear-start, var(--fade-clear-x, var(--fade-clear, 0px)));
}
@utility fade-clear-end-var {
    --tw-fade-clear-end: var(--fade-clear-end, var(--fade-clear-x, var(--fade-clear, 0px)));
}
/*
Sets the pinned bar size. A pure setter: on its own it turns nothing on, because
nothing reads --tw-fade-scrollbar-width unless a fade-scrollbar-safe-* class is.
That split is deliberate. The property inherits, so its most useful home is an
ancestor -- <body class="fade-scrollbar-width-lg"> to set a house style once. A
setter that also enabled would pin and gutter the page's own scrollbar as a side
effect of stating a preference.

[length] only, with no --value(integer) branch. Elsewhere a bare integer means
spacing steps; here it would read as pixels to anyone typing it, and the two
answers differ by 4x. Refusing the ambiguous form is better than picking a side.
Arbitrary negative lengths still compile because they are valid <length> values;
the scrollbar consumers clamp them to 0px before they reach geometry or masks.
*/
@utility fade-scrollbar-width-* {
    --tw-fade-scrollbar-width: --value(--fade-scrollbar-width-*, [length]);
}

@layer utilities {
    .fade,
    .fade-y,
    .fade-top,
    .fade-bottom,
    .fade-x,
    .fade-start,
    .fade-end {
        --tw-fade-size-default: min(12%, var(--fade-size-md, calc(var(--spacing, 0.25rem) * 12)));
        --tw-fade-travel-active: var(--tw-fade-travel, var(--fade-travel-sm, calc(var(--spacing, 0.25rem) * 8)));
        /*
        Keep scroll animation ranges off the exact 0% / 100% endpoints. Chromium
        can otherwise retain a sampled leading fade when a mounted scrollport's
        content collapses from scrollable to non-scrollable.
        */
        --tw-fade-scroll-epsilon: 0.1px;
        --tw-fade-identity-mask: linear-gradient(#000, #000);
        --tw-fade-edge-size-t: var(--tw-fade-size-top, var(--tw-fade-size-y, var(--tw-fade-size, var(--tw-fade-size-default))));
        --tw-fade-edge-size-b: var(--tw-fade-size-bottom, var(--tw-fade-size-y, var(--tw-fade-size, var(--tw-fade-size-default))));
        --tw-fade-edge-size-l: var(--tw-fade-size-start, var(--tw-fade-size-x, var(--tw-fade-size, var(--tw-fade-size-default))));
        --tw-fade-edge-size-r: var(--tw-fade-size-end, var(--tw-fade-size-x, var(--tw-fade-size, var(--tw-fade-size-default))));
        --tw-fade-edge-clear-t: var(--tw-fade-clear-top, var(--tw-fade-clear-y, var(--tw-fade-clear, 0px)));
        --tw-fade-edge-clear-b: var(--tw-fade-clear-bottom, var(--tw-fade-clear-y, var(--tw-fade-clear, 0px)));
        --tw-fade-edge-clear-l: var(--tw-fade-clear-start, var(--tw-fade-clear-x, var(--tw-fade-clear, 0px)));
        --tw-fade-edge-clear-r: var(--tw-fade-clear-end, var(--tw-fade-clear-x, var(--tw-fade-clear, 0px)));
        --tw-fade-edge-band-t: calc(var(--tw-fade-edge-size-t) * var(--tw-fade-t));
        --tw-fade-edge-band-b: calc(var(--tw-fade-edge-size-b) * var(--tw-fade-b));
        --tw-fade-edge-band-l: calc(var(--tw-fade-edge-size-l) * var(--tw-fade-l));
        --tw-fade-edge-band-r: calc(var(--tw-fade-edge-size-r) * var(--tw-fade-r));
        /*
        Decouple edge transparency from band growth. --tw-fade-t..r drive the
        band WIDTH (above), so the band eases open over the full travel distance.
        But the ALPHA at the very edge is driven by --tw-fade-alpha-*, a
        saturated copy that reaches full transparency within travel/onset of
        scroll. This covers the overflow clip almost immediately (no hard cut
        during early scroll) while the band still widens cosmetically over the
        whole travel. --tw-fade-onset = how fast the edge goes transparent
        relative to the travel; higher = snappier clip coverage. At t=0 alpha is
        also 0, so a flush (unscrolled) edge still shows no fade.
        */
        --tw-fade-onset: 8;
        --tw-fade-alpha-t: min(1, calc(var(--tw-fade-t) * var(--tw-fade-onset)));
        --tw-fade-alpha-b: min(1, calc(var(--tw-fade-b) * var(--tw-fade-onset)));
        --tw-fade-alpha-l: min(1, calc(var(--tw-fade-l) * var(--tw-fade-onset)));
        --tw-fade-alpha-r: min(1, calc(var(--tw-fade-r) * var(--tw-fade-onset)));
        --tw-fade-gradient-t: linear-gradient(
            to bottom,
            #000 0 var(--tw-fade-edge-clear-t),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-t))) var(--tw-fade-edge-clear-t),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-t) * 0.983))
                calc(var(--tw-fade-edge-clear-t) + var(--tw-fade-edge-band-t) * 0.08333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-t) * 0.933))
                calc(var(--tw-fade-edge-clear-t) + var(--tw-fade-edge-band-t) * 0.16667),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-t) * 0.854))
                calc(var(--tw-fade-edge-clear-t) + var(--tw-fade-edge-band-t) * 0.25),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-t) * 0.75))
                calc(var(--tw-fade-edge-clear-t) + var(--tw-fade-edge-band-t) * 0.33333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-t) * 0.629))
                calc(var(--tw-fade-edge-clear-t) + var(--tw-fade-edge-band-t) * 0.41667),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-t) * 0.5))
                calc(var(--tw-fade-edge-clear-t) + var(--tw-fade-edge-band-t) * 0.5),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-t) * 0.371))
                calc(var(--tw-fade-edge-clear-t) + var(--tw-fade-edge-band-t) * 0.58333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-t) * 0.25))
                calc(var(--tw-fade-edge-clear-t) + var(--tw-fade-edge-band-t) * 0.66667),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-t) * 0.146))
                calc(var(--tw-fade-edge-clear-t) + var(--tw-fade-edge-band-t) * 0.75),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-t) * 0.067))
                calc(var(--tw-fade-edge-clear-t) + var(--tw-fade-edge-band-t) * 0.83333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-t) * 0.017))
                calc(var(--tw-fade-edge-clear-t) + var(--tw-fade-edge-band-t) * 0.91667),
            rgb(0 0 0 / 1) calc(var(--tw-fade-edge-clear-t) + var(--tw-fade-edge-band-t))
        );
        --tw-fade-gradient-b: linear-gradient(
            to top,
            #000 0 var(--tw-fade-edge-clear-b),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-b))) var(--tw-fade-edge-clear-b),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-b) * 0.983))
                calc(var(--tw-fade-edge-clear-b) + var(--tw-fade-edge-band-b) * 0.08333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-b) * 0.933))
                calc(var(--tw-fade-edge-clear-b) + var(--tw-fade-edge-band-b) * 0.16667),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-b) * 0.854))
                calc(var(--tw-fade-edge-clear-b) + var(--tw-fade-edge-band-b) * 0.25),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-b) * 0.75))
                calc(var(--tw-fade-edge-clear-b) + var(--tw-fade-edge-band-b) * 0.33333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-b) * 0.629))
                calc(var(--tw-fade-edge-clear-b) + var(--tw-fade-edge-band-b) * 0.41667),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-b) * 0.5))
                calc(var(--tw-fade-edge-clear-b) + var(--tw-fade-edge-band-b) * 0.5),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-b) * 0.371))
                calc(var(--tw-fade-edge-clear-b) + var(--tw-fade-edge-band-b) * 0.58333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-b) * 0.25))
                calc(var(--tw-fade-edge-clear-b) + var(--tw-fade-edge-band-b) * 0.66667),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-b) * 0.146))
                calc(var(--tw-fade-edge-clear-b) + var(--tw-fade-edge-band-b) * 0.75),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-b) * 0.067))
                calc(var(--tw-fade-edge-clear-b) + var(--tw-fade-edge-band-b) * 0.83333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-b) * 0.017))
                calc(var(--tw-fade-edge-clear-b) + var(--tw-fade-edge-band-b) * 0.91667),
            rgb(0 0 0 / 1) calc(var(--tw-fade-edge-clear-b) + var(--tw-fade-edge-band-b))
        );
        --tw-fade-gradient-l: linear-gradient(
            to right,
            #000 0 var(--tw-fade-edge-clear-l),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-l))) var(--tw-fade-edge-clear-l),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-l) * 0.983))
                calc(var(--tw-fade-edge-clear-l) + var(--tw-fade-edge-band-l) * 0.08333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-l) * 0.933))
                calc(var(--tw-fade-edge-clear-l) + var(--tw-fade-edge-band-l) * 0.16667),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-l) * 0.854))
                calc(var(--tw-fade-edge-clear-l) + var(--tw-fade-edge-band-l) * 0.25),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-l) * 0.75))
                calc(var(--tw-fade-edge-clear-l) + var(--tw-fade-edge-band-l) * 0.33333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-l) * 0.629))
                calc(var(--tw-fade-edge-clear-l) + var(--tw-fade-edge-band-l) * 0.41667),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-l) * 0.5))
                calc(var(--tw-fade-edge-clear-l) + var(--tw-fade-edge-band-l) * 0.5),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-l) * 0.371))
                calc(var(--tw-fade-edge-clear-l) + var(--tw-fade-edge-band-l) * 0.58333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-l) * 0.25))
                calc(var(--tw-fade-edge-clear-l) + var(--tw-fade-edge-band-l) * 0.66667),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-l) * 0.146))
                calc(var(--tw-fade-edge-clear-l) + var(--tw-fade-edge-band-l) * 0.75),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-l) * 0.067))
                calc(var(--tw-fade-edge-clear-l) + var(--tw-fade-edge-band-l) * 0.83333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-l) * 0.017))
                calc(var(--tw-fade-edge-clear-l) + var(--tw-fade-edge-band-l) * 0.91667),
            rgb(0 0 0 / 1) calc(var(--tw-fade-edge-clear-l) + var(--tw-fade-edge-band-l))
        );
        --tw-fade-gradient-r: linear-gradient(
            to left,
            #000 0 var(--tw-fade-edge-clear-r),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-r))) var(--tw-fade-edge-clear-r),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-r) * 0.983))
                calc(var(--tw-fade-edge-clear-r) + var(--tw-fade-edge-band-r) * 0.08333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-r) * 0.933))
                calc(var(--tw-fade-edge-clear-r) + var(--tw-fade-edge-band-r) * 0.16667),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-r) * 0.854))
                calc(var(--tw-fade-edge-clear-r) + var(--tw-fade-edge-band-r) * 0.25),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-r) * 0.75))
                calc(var(--tw-fade-edge-clear-r) + var(--tw-fade-edge-band-r) * 0.33333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-r) * 0.629))
                calc(var(--tw-fade-edge-clear-r) + var(--tw-fade-edge-band-r) * 0.41667),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-r) * 0.5))
                calc(var(--tw-fade-edge-clear-r) + var(--tw-fade-edge-band-r) * 0.5),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-r) * 0.371))
                calc(var(--tw-fade-edge-clear-r) + var(--tw-fade-edge-band-r) * 0.58333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-r) * 0.25))
                calc(var(--tw-fade-edge-clear-r) + var(--tw-fade-edge-band-r) * 0.66667),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-r) * 0.146))
                calc(var(--tw-fade-edge-clear-r) + var(--tw-fade-edge-band-r) * 0.75),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-r) * 0.067))
                calc(var(--tw-fade-edge-clear-r) + var(--tw-fade-edge-band-r) * 0.83333),
            rgb(0 0 0 / calc(1 - var(--tw-fade-alpha-r) * 0.017))
                calc(var(--tw-fade-edge-clear-r) + var(--tw-fade-edge-band-r) * 0.91667),
            rgb(0 0 0 / 1) calc(var(--tw-fade-edge-clear-r) + var(--tw-fade-edge-band-r))
        );
        --tw-fade-mask-l: var(--tw-fade-ltr-start-layer, var(--tw-fade-identity-mask));
        --tw-fade-mask-r: var(--tw-fade-ltr-end-layer, var(--tw-fade-identity-mask));
        --tw-fade-animation-l: var(--tw-fade-ltr-start-animation, none);
        --tw-fade-animation-r: var(--tw-fade-ltr-end-animation, none);
        --tw-fade-timeline-l: var(--tw-fade-ltr-start-timeline, none);
        --tw-fade-timeline-r: var(--tw-fade-ltr-end-timeline, none);
        --tw-fade-animation-range-l: var(--tw-fade-ltr-start-animation-range, normal);
        --tw-fade-animation-range-r: var(--tw-fade-ltr-end-animation-range, normal);
        /*
        Neutral block-axis defaults. Unlike the l/r hooks above, the t/b
        animation/timeline/range vars are not @property-registered and are set
        only in the axis blocks below, so without a local default here a nested
        fade child would inherit a parent's vertical hook and run a spurious
        (inert) second scroll animation. The axis blocks override these by
        source order at equal specificity, so top-level fades are unaffected.
        */
        --tw-fade-animation-t: none;
        --tw-fade-animation-b: none;
        --tw-fade-timeline-t: none;
        --tw-fade-timeline-b: none;
        --tw-fade-animation-range-t: normal;
        --tw-fade-animation-range-b: normal;
        /*
        Scrollbar-protection strip (opt-in, inert by default). An extra opaque
        mask layer covering only the inline-end scrollbar column, unioned onto
        the fade via mask-composite:add. Union can only ADD opacity, so it
        restores that column to fully opaque -- shielding a classic scrollbar
        from the fade -- while leaving the content fade untouched. Width defaults
        to 0px (covers nothing => no-op); fade-scrollbar-safe-y widens it. Position
        is inline-end (right in LTR; the :dir(rtl) block flips it to left).
        */
        --tw-fade-scrollbar-pos: 100% 0%;
        /*
        The inline-end gradient is inset by the same width, which fixes a second,
        quieter symptom of the same root cause. Mask percentages resolve against
        the border box (gutter included) while content stops at the scrollport
        edge, so a right-edge ramp authored to reach zero at 100% reaches zero
        inside the GUTTER -- and over real content it only ever gets
        (size - gutter)/size of the way down. Measured with a 60px band and the
        15px default bar, the last content pixel is still 40/255 opaque, and
        161/255 under a 26px band: the fade visibly fails to complete, leaving a
        hard edge exactly where it should have dissolved. Tighter bands are hit
        harder, since the gutter eats a larger share of the ramp. Sizing the layer to
        calc(100% - scrollbar) lands the ramp's end on the content edge instead,
        and the strip restores the gutter column afterwards.

        This is only expressible because the width is pinned rather than guessed;
        at the 0px default calc(100% - 0px) is 100% and nothing changes.
        */
        --tw-fade-mask-size-l: 100% 100%;
        --tw-fade-mask-size-r: calc(100% - var(--tw-fade-scrollbar, 0px)) 100%;
        --tw-fade-mask-pos-l: 0% 0%;
        --tw-fade-mask-pos-r: 0% 0%;
        /*
        Mask layers accumulate bottom-to-top: the LAST listed layer seeds the
        stack and each earlier layer composites onto what's below it. So the four
        edge gradients sit at the bottom and intersect among themselves, and the
        strips must be listed FIRST with add to union onto that intersection --
        add can only raise opacity, restoring the scrollbar columns. A 0px strip
        covers nothing, so add contributes nothing and base fades are unchanged.
        */
        mask-image:
            var(--tw-fade-identity-mask),
            var(--tw-fade-identity-mask),
            var(--tw-fade-mask-t, var(--tw-fade-identity-mask)),
            var(--tw-fade-mask-b, var(--tw-fade-identity-mask)),
            var(--tw-fade-mask-l, var(--tw-fade-identity-mask)),
            var(--tw-fade-mask-r, var(--tw-fade-identity-mask));
        mask-composite: add, add, intersect, intersect, intersect, intersect;
        mask-repeat: no-repeat;
        /*
        The strips use padding-box origin; the gradients keep the default
        border-box. The gutter sits between the padding and border edges, so a
        border-box-anchored strip is pushed outward by the border and straddles
        it: measured on a 5px border with an 11px bar, the strip covered the
        border plus only 6 of the 11 gutter pixels, leaving 5px of scrollbar
        still faded. Padding-box is exactly right because CSS Overflow 3 5.1
        folds the reserved gutter INTO the padding area for painting purposes,
        so the padding box's inline-end edge is the gutter's outer edge.
        */
        mask-origin: padding-box, padding-box, border-box, border-box, border-box, border-box;
        mask-size:
            100% var(--tw-fade-scrollbar-block, 0px),
            var(--tw-fade-scrollbar, 0px) 100%,
            100% 100%,
            100% calc(100% - var(--tw-fade-scrollbar-block, 0px)),
            var(--tw-fade-mask-size-l),
            var(--tw-fade-mask-size-r);
        mask-position:
            0% 100%,
            var(--tw-fade-scrollbar-pos),
            0% 0%,
            0% 0%,
            var(--tw-fade-mask-pos-l),
            var(--tw-fade-mask-pos-r);
    }

    .fade:where(:dir(rtl)),
    .fade-y:where(:dir(rtl)),
    .fade-top:where(:dir(rtl)),
    .fade-bottom:where(:dir(rtl)),
    .fade-x:where(:dir(rtl)),
    .fade-start:where(:dir(rtl)),
    .fade-end:where(:dir(rtl)) {
        --tw-fade-edge-size-l: var(--tw-fade-size-end, var(--tw-fade-size-x, var(--tw-fade-size, var(--tw-fade-size-default))));
        --tw-fade-edge-size-r: var(--tw-fade-size-start, var(--tw-fade-size-x, var(--tw-fade-size, var(--tw-fade-size-default))));
        --tw-fade-edge-clear-l: var(--tw-fade-clear-end, var(--tw-fade-clear-x, var(--tw-fade-clear, 0px)));
        --tw-fade-edge-clear-r: var(--tw-fade-clear-start, var(--tw-fade-clear-x, var(--tw-fade-clear, 0px)));
        /*
        RTL puts the vertical scrollbar on the left, so the shield moves there
        and the INLINE-END inset swaps to the left layer with it. The inset layer
        is right-aligned (100% 0%) so it occupies everything to the right of the
        gutter, putting the ramp's transparent end on the content's left edge.
        At the 0px default the layer is full-size and the alignment is moot.
        */
        --tw-fade-scrollbar-pos: 0% 0%;
        --tw-fade-mask-size-l: calc(100% - var(--tw-fade-scrollbar, 0px)) 100%;
        --tw-fade-mask-size-r: 100% 100%;
        --tw-fade-mask-pos-l: 100% 0%;
        --tw-fade-mask-pos-r: 0% 0%;
        --tw-fade-mask-l: var(--tw-fade-rtl-end-layer, var(--tw-fade-identity-mask));
        --tw-fade-mask-r: var(--tw-fade-rtl-start-layer, var(--tw-fade-identity-mask));
        --tw-fade-animation-l: var(--tw-fade-rtl-end-animation, none);
        --tw-fade-animation-r: var(--tw-fade-rtl-start-animation, none);
        --tw-fade-timeline-l: var(--tw-fade-rtl-end-timeline, none);
        --tw-fade-timeline-r: var(--tw-fade-rtl-start-timeline, none);
        --tw-fade-animation-range-l: var(--tw-fade-rtl-end-animation-range, normal);
        --tw-fade-animation-range-r: var(--tw-fade-rtl-start-animation-range, normal);
    }

    .fade,
    .fade-y,
    .fade-top {
        --tw-fade-mask-t: var(--tw-fade-gradient-t);
        --tw-fade-animation-t: tw-fade-travel-t;
        --tw-fade-timeline-t: scroll(self y);
        --tw-fade-animation-range-t: var(--tw-fade-scroll-epsilon)
            max(var(--tw-fade-scroll-epsilon), var(--tw-fade-travel-active));
    }

    .fade,
    .fade-y,
    .fade-bottom {
        --tw-fade-mask-b: var(--tw-fade-gradient-b);
        --tw-fade-animation-b: tw-fade-travel-b;
        --tw-fade-timeline-b: scroll(self y);
        --tw-fade-animation-range-b: min(
                calc(100% - var(--tw-fade-travel-active)),
                calc(100% - var(--tw-fade-scroll-epsilon))
            )
            calc(100% - var(--tw-fade-scroll-epsilon));
    }

    .fade,
    .fade-x,
    .fade-start {
        --tw-fade-ltr-start-layer: var(--tw-fade-gradient-l);
        --tw-fade-rtl-start-layer: var(--tw-fade-gradient-r);
        --tw-fade-ltr-start-animation: tw-fade-travel-l;
        --tw-fade-rtl-start-animation: tw-fade-travel-r-leading;
        --tw-fade-ltr-start-timeline: scroll(self inline);
        --tw-fade-rtl-start-timeline: scroll(self inline);
        --tw-fade-ltr-start-animation-range: var(--tw-fade-scroll-epsilon)
            max(var(--tw-fade-scroll-epsilon), var(--tw-fade-travel-active));
        --tw-fade-rtl-start-animation-range: var(--tw-fade-scroll-epsilon)
            max(var(--tw-fade-scroll-epsilon), var(--tw-fade-travel-active));
    }

    .fade,
    .fade-x,
    .fade-end {
        --tw-fade-ltr-end-layer: var(--tw-fade-gradient-r);
        --tw-fade-rtl-end-layer: var(--tw-fade-gradient-l);
        --tw-fade-ltr-end-animation: tw-fade-travel-r;
        --tw-fade-rtl-end-animation: tw-fade-travel-l-trailing;
        --tw-fade-ltr-end-timeline: scroll(self inline);
        --tw-fade-rtl-end-timeline: scroll(self inline);
        --tw-fade-ltr-end-animation-range: min(
                calc(100% - var(--tw-fade-travel-active)),
                calc(100% - var(--tw-fade-scroll-epsilon))
            )
            calc(100% - var(--tw-fade-scroll-epsilon));
        --tw-fade-rtl-end-animation-range: min(
                calc(100% - var(--tw-fade-travel-active)),
                calc(100% - var(--tw-fade-scroll-epsilon))
            )
            calc(100% - var(--tw-fade-scroll-epsilon));
    }

    @supports (animation-timeline: scroll()) {
        .fade,
        .fade-y,
        .fade-top,
        .fade-bottom,
        .fade-x,
        .fade-start,
        .fade-end {
            animation:
                var(--tw-fade-animation-t, none) auto linear both,
                var(--tw-fade-animation-b, none) auto linear both,
                var(--tw-fade-animation-l, none) auto linear both,
                var(--tw-fade-animation-r, none) auto linear both;
            animation-timeline:
                var(--tw-fade-timeline-t, none),
                var(--tw-fade-timeline-b, none),
                var(--tw-fade-timeline-l, none),
                var(--tw-fade-timeline-r, none);
            animation-range:
                var(--tw-fade-animation-range-t, normal),
                var(--tw-fade-animation-range-b, normal),
                var(--tw-fade-animation-range-l, normal),
                var(--tw-fade-animation-range-r, normal);
        }
    }

    @supports not (animation-timeline: scroll()) {
        .fade,
        .fade-y,
        .fade-top,
        .fade-bottom,
        .fade-x,
        .fade-start,
        .fade-end {
            --tw-fade-t: 1;
            --tw-fade-b: 1;
            --tw-fade-l: 1;
            --tw-fade-r: 1;
        }
    }

    .fade-none {
        --tw-fade-t: 0 !important;
        --tw-fade-b: 0 !important;
        --tw-fade-l: 0 !important;
        --tw-fade-r: 0 !important;
    }

    .fade-none-y {
        --tw-fade-t: 0 !important;
        --tw-fade-b: 0 !important;
    }

    .fade-none-x {
        --tw-fade-l: 0 !important;
        --tw-fade-r: 0 !important;
    }

    .fade-always {
        --tw-fade-t: 1 !important;
        --tw-fade-b: 1 !important;
        --tw-fade-l: 1 !important;
        --tw-fade-r: 1 !important;
    }

    .fade-always-y {
        --tw-fade-t: 1 !important;
        --tw-fade-b: 1 !important;
    }

    .fade-always-x {
        --tw-fade-l: 1 !important;
        --tw-fade-r: 1 !important;
    }

    /*
    Opt-in: keep a classic (space-consuming) scrollbar out of the fade.

    Why a mask hits the scrollbar at all: masking applies to the element after it
    and its descendants are drawn to one temporary canvas, and a "visible
    scrolling mechanism" is part of that canvas. Filter Effects says so in as
    many words for filter, CSS Masking says so for clip-path, and mask inherits
    it structurally. Overlay scrollbars (macOS/iOS/Android default) are composited
    separately and escape -- which is why this is invisible on a Mac and obvious
    on Windows.

    Why the strip's width can't be derived: the reserved gutter sits inside the
    mask's reference boxes by normative reference (CSS Overflow 3 folds it into
    the padding area for background positioning; CSS Masking defines the mask
    boxes as the background boxes), so no <coord-box> isolates it. Container
    query units DO measure it -- 100cqi excludes the gutter -- but cq units
    resolve against an ancestor container, so only descendants can read them,
    never the masked element itself. The width is therefore knowable everywhere
    except where it is needed.

    So it is not derived, it is DECLARED. ::-webkit-scrollbar pins the bar to
    exactly --tw-fade-scrollbar-width in Blink and WebKit on every platform, and
    the strip is set from the same custom property, so bar and strip are equal by
    construction rather than by coincidence. That also survives page zoom: a
    native bar holds a constant physical size, so its width in CSS px drifts as
    1/zoom (15 -> 12 -> 7.5 from 1x to 2x), while two author-declared lengths
    scale together and stay aligned.

    scrollbar-width and scrollbar-color are deliberately NOT set here: specifying
    either one makes Blink discard ::-webkit-scrollbar customization entirely
    (scrollbar-width does the same in WebKit), which would cancel the pin and
    take the gutter to 0 while leaving a 15px strip sitting on top of content.
    They are confined to the Gecko branch below, where they are the only levers
    that exist. The same collision applies to Tailwind's own utilities that set
    those properties -- scrollbar-thin / -auto / -none for the width, and
    scrollbar-thumb-* / scrollbar-track-* for the colour (there is no
    scrollbar-color-* utility) -- so putting any of them on the same element
    cancels the pin. Use fade-scrollbar-width-* for the size and
    ::-webkit-scrollbar-track / -thumb for the colours, which is why the width
    utility exists at all.
    */
    /*
    THE SUFFIX IS THE SCROLL AXIS, NOT THE FADED EDGE. -y is the bar you get
    from scrolling on y: the VERTICAL bar, at the inline end. -x is the
    horizontal bar along the block end. This follows overflow-y / overflow-x,
    which is the model an author already has, and it deliberately does NOT
    follow this plugin's own fade-y (top+bottom edges) -- the noun differs, and
    in practice the two agree anyway: a y-scroller wants fade-y and
    fade-scrollbar-safe-y, and all three axes line up.

    Only -y stabilizes a gutter, because only the inline axis has one to
    stabilize. -x deliberately omits it: scrollbar-gutter reserves nothing on
    the block axis, and setting it on an x-only scroller would reserve an inline
    gutter for a vertical bar the author just said they do not have.
    */
    /*
    THE WHOLE UTILITY REQUIRES SCROLL GATING. Not just the strip -- the pin too.

    Without animation-timeline: scroll() the plugin takes its static fallback,
    which pins every selected fade ON regardless of whether the container
    overflows (see the @supports not (animation-timeline: scroll()) block). A
    faded container with no overflow has no reserved gutter, so the strip lands
    on content: measured in WebKit, a plain overflow-auto fade-y container whose
    content does not overflow renders the inline-end fade to fully transparent
    and then a hard 15px opaque band of content beyond it -- the exact inversion
    of what this utility is for, on markup that never mentions fade-always.

    Dropping only the strip is not enough, because the pin is what makes the bar
    classic in the first place. Pinned-but-unshielded is strictly worse than not
    opting in at all: on macOS it manufactures a space-consuming bar and then
    lets the fade dim it, converting a platform with no bug into one with the
    bug. So the entire opt-in stands down together, and those engines get their
    native behaviour -- overlay bars on macOS, which the mask never touches.

    This costs nothing where the feature works: every engine that can shield a
    scrollbar (Blink, WebKit 26+) supports scroll-driven animations. It removes
    the feature on Safari 17.x / 18.x and on release Firefox with the
    scroll-driven-animation pref off, where it could only have done harm.
    */
    @supports (animation-timeline: scroll()) {
    .fade-scrollbar-safe-y,
    .fade-scrollbar-safe-xy {
        /*
        Required, not cosmetic: without a stable gutter the bar appears only
        while the content overflows, so the strip would be right when it does
        and a bright slab over content when it doesn't. Note this only takes
        effect once the pin below has made the bar classic -- scrollbar-gutter
        reserves nothing for overlay bars, which consume no space to begin with.

        Blink honours this for custom bars and reserves the gutter even when the
        content does not overflow. WebKit does not: measured, gutter 0 on a
        non-overflowing container while the strip is still 15px wide. That
        residual is documented, and an author can close it with
        overflow-y: scroll, which forces the gutter in WebKit too (measured 15px,
        strip landing exactly on the track).
        */
        scrollbar-gutter: stable;
    }

    @supports selector(::-webkit-scrollbar) {
        .fade-scrollbar-safe-y,
        .fade-scrollbar-safe-xy {
            --tw-fade-scrollbar: max(0px, var(--tw-fade-scrollbar-width, 15px));
        }

        /*
        The block axis, for the horizontal bar. Only safe when the container
        really does overflow horizontally: unlike the inline gutter, this one is
        reserved only while a bar is actually present, and no scrollbar-gutter
        value changes that -- see the --tw-fade-scrollbar-block registration for
        the measurements. CSS cannot detect horizontal overflow; the author can.
        That is the whole reason the axis is named rather than inferred.
        */
        .fade-scrollbar-safe-x,
        .fade-scrollbar-safe-xy {
            --tw-fade-scrollbar-block: max(0px, var(--tw-fade-scrollbar-width, 15px));
        }

        /*
        The pin. Declaring a width here forces a classic, space-consuming bar of
        exactly this size on every platform -- including macOS, where the default
        would otherwise be an overlay bar. That is the trade this utility makes:
        it takes ownership of the scrollbar's geometry in exchange for being
        exact rather than approximate.

        Both dimensions are pinned on all three classes, even though -y shields
        only the inline bar. Both engines treat the custom-scrollbar opt-in as
        per-ELEMENT, not per-axis: an unscoped ::-webkit-scrollbar rule turns the
        horizontal bar classic too, whether or not this rule mentions height.
        Omitting height therefore does not restore the overlay bar, it just
        surrenders the size -- measured, the manufactured horizontal bar grows
        from 11px to the 16px UA default while remaining equally faded. Pinning
        it keeps that bar small and, more importantly, keeps it a known quantity
        that -x and -xy can shield exactly.
        */
        .fade-scrollbar-safe-y::-webkit-scrollbar,
        .fade-scrollbar-safe-x::-webkit-scrollbar,
        .fade-scrollbar-safe-xy::-webkit-scrollbar {
            width: max(0px, var(--tw-fade-scrollbar-width, 15px));
            height: max(0px, var(--tw-fade-scrollbar-width, 15px));
        }

        .fade-scrollbar-safe-y::-webkit-scrollbar-track,
        .fade-scrollbar-safe-x::-webkit-scrollbar-track,
        .fade-scrollbar-safe-xy::-webkit-scrollbar-track {
            background: transparent;
        }

        .fade-scrollbar-safe-y::-webkit-scrollbar-thumb,
        .fade-scrollbar-safe-x::-webkit-scrollbar-thumb,
        .fade-scrollbar-safe-xy::-webkit-scrollbar-thumb {
            background: var(--tw-fade-scrollbar-thumb, color-mix(in srgb, currentColor 30%, transparent));
            border-radius: 999px;
        }
    }

    /*
    Gecko ignores ::-webkit-scrollbar, so its bar cannot be pinned -- and its
    overlay-vs-classic mode cannot be detected either (there is no media feature
    for it; @media (-moz-overlay-scrollbars) is dropped as unknown, and no
    combination of scrollbar-width / -color / -gutter forces a classic bar on
    macOS). A strip here would be correct on Windows and Linux and a hard opaque
    slab over content on macOS, with no way to tell which. Since a missed strip
    damages content while the bug it prevents only dims chrome, a Gecko build
    that passes the outer scroll-animation gate gets no strip: its bar is merely
    made thin, and the fade over it remains a documented limitation. Release
    Firefox fails that gate and skips the whole opt-in, keeping its native bar.
    */
    @supports not selector(::-webkit-scrollbar) {
        .fade-scrollbar-safe-y,
        .fade-scrollbar-safe-x,
        .fade-scrollbar-safe-xy {
            scrollbar-width: thin;
            scrollbar-color: var(--tw-fade-scrollbar-thumb, color-mix(in srgb, currentColor 30%, transparent))
                transparent;
        }
    }
    }
}
