/* ===========================================================================
 * THE APP'S ONE SCROLLBAR SKIN.
 *
 * WHY IT IS HERE AND NOT IN `web/`. This repo carries two front end trees,
 * and the rule below is unscoped on purpose: it has to reach the document
 * scrollbar, every legacy panel, every compiled Svelte panel and every
 * surface nobody has written yet. Only `client/css` may write a rule like
 * that. `web/src/opscenter/app.css` forbids itself from doing so in its own
 * header ("A bare `*` reset or a `body { font-family }` here would repaint
 * the terminal, the toasts, the sidebar and every modal in the app"), and
 * `web/src/app.css` is a Tailwind utilities entry that deliberately imports
 * no preflight. So the RULE lives in this tree and the COLOUR lives in the
 * other one: `web/src/opscenter/tokens.css` is the only file in the repo
 * allowed a colour literal, and it derives `--oc-scrollbar-*` from each
 * theme's own accent and ground. Both stylesheets load into ONE document
 * (client/index.html links them unconditionally), so one copy covers both
 * trees, and a second copy would be a second source of truth for one fact.
 *
 * TWO MECHANISMS, AND THEY CANNOT SAY THE SAME THING.
 *
 *   - The WebKit pseudo elements (`::-webkit-scrollbar` and friends) can
 *     express everything this design needs: the bar's thickness, the track,
 *     the thumb, its corner radius, the inset that keeps it off the track's
 *     edge, a minimum thumb length so a long list does not produce a two
 *     pixel nub, and hover and active states.
 *
 *   - The standard properties can express two things and no more:
 *     `scrollbar-width` takes a KEYWORD (`auto` / `thin` / `none`), never a
 *     length, and `scrollbar-color` takes exactly two colours, thumb then
 *     track. There is no radius, no inset, no minimum length and no hover or
 *     active state anywhere in the standard mechanism.
 *
 * THEY CANNOT BOTH BE SWITCHED ON. In Chromium and WebKit, an element whose
 * computed `scrollbar-color` or `scrollbar-width` is anything other than
 * `auto` DROPS its `::-webkit-scrollbar` pseudo elements entirely. Setting
 * both would therefore not be belt and braces, it would silently throw away
 * the radius, the inset, the minimum length and both interaction states.
 * `scrollbar-color` also inherits, so setting it on `:root` alone would
 * disarm the pseudo elements on every descendant too.
 *
 * So the standard properties are declared ONLY inside
 * `@supports not selector(::-webkit-scrollbar)`: an engine that has the
 * pseudo elements takes the rich path, an engine that does not takes the two
 * colours and a thin bar. An engine too old to evaluate `selector()` at all
 * leaves the block unapplied, which is the right answer for it as well.
 *
 * WHAT THIS FILE DELIBERATELY DOES NOT DO. It never sets `scrollbar-gutter`,
 * which would reserve a permanent channel and steal width from a phone that
 * has no bar to put in it. It never makes a bar overlay content: the thumb
 * has to stay grabbable at its usual width the moment it appears, never on
 * top of the text it would then obscure.
 *
 * ALWAYS REACHABLE, BRIGHTER UNDER THE POINTER (Joe (ccsliinc), 2026-09-30,
 * live 1.12.21-preview.364: "when hovering over an area on a page, the
 * scrollbars dont always show up and its a little janky"). This REPLACES the
 * #768 hide-until-hover design. ROOT CAUSE: the thumb was `transparent` at
 * rest and only painted through an unscoped `:hover::-webkit-scrollbar-thumb`
 * / `:focus-within::...` rule, i.e. the scrollbar's paint depended on the
 * state of its SCROLLING ELEMENT (or an ancestor of it). Chromium does not
 * reliably invalidate a scrollbar's pseudo element paint when the owning
 * element's `:hover` flips (it repaints on the next unrelated layout, which
 * is the janky lag), a scroller that is `pointer-events: none`, portalled, or
 * whose hovered child sits in another subtree never matched at all (the bar
 * "does not always show up"), and the bar took its full 11px of layout while
 * invisible, so a hidden bar was also dead space. The fix is that NOTHING
 * about the bar depends on an ancestor's state any more: the thumb always
 * paints a quiet themed colour whenever the area actually overflows (a
 * scroller that does not overflow has no bar at all), and brightening uses
 * only the thumb's OWN `:hover` / `:active`, which the engine repaints
 * correctly. No rule here changes width, border, inset or size on any state,
 * so hover and scroll cause no layout shift (tests/python/design_system/
 * test_scrollbar_always_reachable.py pins that).
 *
 * `scrollbar-gutter` is still NOT set here: an app-wide reserved channel
 * would steal width from every non-overflowing panel and from a phone. A
 * surface whose geometry is derived from one measured width reserves it
 * itself (`web/src/opscenter/app.css`).
 *
 * A COARSE POINTER IS LEFT ALONE, AND THAT IS A MEASUREMENT RATHER THAN A
 * PREFERENCE. A painted scrollbar takes layout width; the platform's own
 * overlay bar on a touch device takes none and fades when it is not needed.
 * Measured on an iPhone 13 viewport against this app on 2026-09-21: the one
 * overflowing panel on the home screen at 390px held 235px of content with
 * this skin off and 224px with it on, and toggling the stylesheet moved the
 * number both ways. Eleven pixels is a real loss on the device this app is
 * driven from, and it buys a pill no finger can grab. So the whole skin sits
 * behind `(hover: hover) and (pointer: fine)` and a phone keeps exactly the
 * scrollbars it has today. Touch scrolling is untouched either way: the same
 * panel scrolled by the same 60px in both states.
 *
 * SURFACES THAT OPT OUT KEEP OPTING OUT. Two rules already in the tree are
 * more specific than anything here and still win:
 * `.xterm-host .xterm-viewport` in styles.css, which hides the bar on every
 * emulator viewport because xterm.js measures that element to decide its
 * column count, and `.settings-tabs` in the same file, whose horizontal tab
 * strip uses a fade rather than a bar. Neither is touched here.
 *
 * =========================================================================== */

:root {
    /* GEOMETRY ONLY. Not one colour in this block, which is what keeps this
       file inside the no-literals rule: every colour below is a `var()` on a
       token web/src/opscenter/tokens.css derives per theme. */

    /* The grab area. 11px is a real target for a mouse and a trackpad
       without reading as a piece of furniture. */
    --scrollbar-size: 11px;
    /* How far the painted thumb sits inside that grab area, per side. The
       thumb keeps the full 11px of hit area and paints 7px of it. */
    --scrollbar-inset: 2px;
    /* THE FLOOR THAT STOPS A TWO PIXEL THUMB. A long archive transcript or a
       full project tree makes the proportional thumb vanishingly short, and
       a thumb shorter than a fingertip is not a control. */
    --scrollbar-thumb-min: 36px;
}

/* ===========================================================================
 * EVERYTHING BELOW IS FOR A POINTER THAT CAN GRAB A THUMB. See the note at
 * the top of this file for the phone measurement that put it behind a gate.
 * =========================================================================== */
@media (hover: hover) and (pointer: fine) {

    /* ---------------------------------------------------------------------------
     * The rich path: Chromium and WebKit.
     * ------------------------------------------------------------------------ */

    ::-webkit-scrollbar {
        width: var(--scrollbar-size);
        height: var(--scrollbar-size);
    }

    /* The channel is quiet at rest and only the thumb is drawn, so a long
       page reads clean but the bar is always there to grab. The corner, where
       a vertical and a horizontal bar meet, is the same value: left alone it
       paints a light grey square that belongs to no theme. */
    ::-webkit-scrollbar-track,
    ::-webkit-scrollbar-corner {
        background-color: transparent;
    }

    /* ALWAYS DRAWN, from a token, on the thumb's own rule and no ancestor's
       state (see the ROOT CAUSE note above). The transparent border plus
       padding-box clipping insets the painted pill without shrinking the
       region the pointer can grab. */
    ::-webkit-scrollbar-thumb {
        background-color: var(--oc-scrollbar-thumb-rest);
        background-clip: padding-box;
        border: var(--scrollbar-inset) solid transparent;
        border-radius: var(--scrollbar-size);
        min-height: var(--scrollbar-thumb-min);
        min-width: var(--scrollbar-thumb-min);
    }

    /* Pointing at the bar cuts the channel in and brightens the thumb. Only
       `background-color` changes, never the `background` shorthand, which
       would reset `background-clip` and fill the inset back in, and never a
       size, so nothing moves. Each selector is the pseudo element's OWN
       state, which the engine repaints reliably. */
    ::-webkit-scrollbar-track:hover {
        background-color: var(--oc-scrollbar-track);
    }

    ::-webkit-scrollbar-thumb:hover {
        background-color: var(--oc-scrollbar-thumb-hover);
    }

    ::-webkit-scrollbar-thumb:active {
        background-color: var(--oc-scrollbar-thumb-active);
    }

    /* ---------------------------------------------------------------------------
     * The standard path, for an engine with no pseudo elements. Read the
     * "THEY CANNOT BOTH BE SWITCHED ON" note above before removing the guard.
     * ------------------------------------------------------------------------ */

    @supports not selector(::-webkit-scrollbar) {
        :root {
            /* `scrollbar-color` inherits, so one declaration on the root
               reaches every scroll container in the document. */
            scrollbar-width: thin;
            scrollbar-color: var(--oc-scrollbar-thumb-rest) transparent;
        }
    }
}
