/* POPUP FOCUS - the one look every popup menu in the app wears, and the
 * look the active terminal cell on a dashboard wears too.
 *
 * ONE RULE, ONE KEYFRAMES, ONE REGISTERED ANGLE. A surface opts in by
 * carrying the `popup-focus` class; it never copies these declarations.
 * The legacy menus add the class where their JS builds the panel, the
 * compiled (web/) menus add it in their markup, and none of them declares
 * its own border, ground or shadow any more. A component that needs a
 * different edge or ground sets one of the `--pf-*` inputs below instead
 * (the dashboard's active terminal cell sets its edge to the session's
 * own accent), so there is still exactly one place the look is drawn.
 *
 * WHY THIS FILE LOADS LAST. It is linked after every other stylesheet in
 * client/index.html, compiled bundle included, so at equal specificity it
 * wins over a menu's own class rule. A Svelte scoped rule is one class
 * heavier, which is why the web/ menus simply stop declaring the three
 * properties this rule owns.
 *
 * THE LOOK, HISTORY IN client/css/session-row-menu.css. A 1px border drawn
 * by the box's OWN background layers (an opaque ground clipped to the
 * padding box over gradients clipped to the border box, behind a
 * transparent border), never by a pseudo-element: a menu scrolls itself,
 * and a positioned pseudo inside a scrolling box drifts across the items.
 * The border is a static top-down gradient, darker at the top; a short
 * bright arc (the sheen) travels one lap of it every 6s; a static 5px
 * accent glow and two flat black drop shadows sit under it. The drop
 * shadows are black, not a token, because they must read on a light theme
 * where every accent token is itself light.
 *
 * THE SHIMMER USED TO SHOW ONLY AT THE TOP, AND THIS IS WHY (measured
 * 2026-09-23, Chromium and WebKit, on a 200x249 kebab menu). The sheen was
 * `--oc-strip-edge` at 60% over a border that fades to `--oc-strip-edge`
 * at the bottom, so the arc added contrast only where the border was still
 * dark: the pixel difference against a sheen-free frame peaked at 31/255
 * on the top edge, fell to 10 to 26 down the sides and was 0 on the whole
 * bottom edge. The arc was moving the whole time; it was invisible for
 * roughly half of every lap. The sheen is now the accent lifted toward the
 * brightest text tier, which is brighter than BOTH ends of the border, so
 * it reads on all four edges, and its arc is about three times as long.
 *
 * WHY A CONIC ARC SPEEDS UP AND SLOWS DOWN. The arc is an angle around the
 * box's centre, so it crosses a short edge in less time than a long one
 * and lingers near the corners. A uniform-speed trace would need an
 * offset-path or a mask per surface; the conic layer costs one background
 * and needs nothing measured, and at 6s a lap the variation reads as a
 * slow glide, not a jump.
 *
 * AN ENGINE WITHOUT @property cannot interpolate `--pf-angle` and flips
 * between the 0deg and 360deg keyframes instead, which paint the same
 * arc, so it shows one still frame rather than a broken pose.
 *
 * REDUCED MOTION shows NO sheen at all, not a parked one: a sheen frozen
 * at 0deg is a bright stub at one spot of the border that reads as a
 * rendering fault. The animation stops and the sheen colour goes
 * transparent, leaving the plain top-down border, the glow and the drop
 * shadows.
 */

@property --pf-angle {
    syntax: '<angle>';
    inherits: false;
    initial-value: 0deg;
}

@keyframes popup-focus-orbit {
    from { --pf-angle: 0deg; }
    to { --pf-angle: 360deg; }
}

.popup-focus {
    --pf-ground: var(--oc-ground-raised);
    --pf-edge-top: var(--oc-line-panel);
    --pf-edge-bottom: var(--oc-strip-edge);
    --pf-sheen: color-mix(in srgb, color-mix(in srgb, var(--oc-orange) 55%, var(--oc-text-bright)) 85%, transparent);
    --pf-glow: color-mix(in srgb, var(--oc-orange) 45%, transparent);
    border: 1px solid transparent;
    background:
        linear-gradient(var(--pf-ground), var(--pf-ground)) padding-box,
        conic-gradient(
            from var(--pf-angle),
            transparent 0deg,
            transparent 130deg,
            var(--pf-sheen) 180deg,
            transparent 230deg,
            transparent 360deg
        ) border-box,
        linear-gradient(to bottom, var(--pf-edge-top), var(--pf-edge-bottom)) border-box;
    box-shadow:
        0 3px 2px var(--pf-glow),
        0 8px 24px rgba(0, 0, 0, 0.55),
        0 2px 6px rgba(0, 0, 0, 0.35);
    animation: popup-focus-orbit 6s linear infinite;
}

/* THE SHEEN THAT TURNS ON THE COMPOSITOR (issue #1809). A surface that stays
 * on screen (the selected terminal cell, a dashboard widget) wears
 * `popup-focus-turn` next to `popup-focus` and carries one child,
 * `<span class="pf-sheen" aria-hidden="true">`. Animating the registered
 * `--pf-angle` re-resolves style, re-lays-out and repaints the whole frame every
 * frame and the GPU re-rasterizes the gradient (measured 2026-10-15: about 85%
 * of the renderer and 79% of the GPU of an idle tab, forever). So here the
 * frame's border is STATIC (the ground and the top-down edge only, no conic
 * layer), and the sheen is a conic square, larger than the frame's diagonal,
 * that ROTATES with `transform`, clipped to a 1px band by a static mask on its
 * host. Only `transform` animates, so no layout, no style recalc, no repaint.
 * `overflow: clip` with a 1px margin lets the host reach over the border while
 * the frame still clips its own content to the rounded edge. The same look,
 * speed (6s a lap) and direction (clockwise) as the bordered menus below,
 * which are short lived and keep the registered-angle lap.
 *
 * THE LAP IS STEPPED, NOT ANIMATED (Carnivore round 3, B12): any running infinite CSS animation keeps the compositor (and
 * WindowServer) producing frames at the display rate, so the ring has no animation. client/js/ambient-ticker.js writes one
 * integer, `--amb-step`, on the host every 250 ms (4 Hz), and the sheen sits at `step x 15deg`: 24 steps is the same 6s lap
 * as before, clockwise, with no transition between steps. The host's one-millisecond `amb-join-dialog-glow` animation
 * (animation-pause.css) is only how the ticker finds its wearers. No ticker, a switched-off type or Reduce Motion = the
 * property is absent, the sheen rests at 0deg. */
.popup-focus.popup-focus-turn {
    --pf-bw: 1px;
    animation: none;
    overflow: clip;
    overflow-clip-margin: 1px;
    background:
        linear-gradient(var(--pf-ground), var(--pf-ground)) padding-box,
        linear-gradient(to bottom, var(--pf-edge-top), var(--pf-edge-bottom)) border-box;
}

/* THE OVERLAY RING, for a surface that must not take a border at all: the
 * dashboard's page terminal, whose frame is bare because its pane's exact
 * rectangle reaches tmux as the session's size. Its sheen host also paints
 * the static top-down edge, so the same look sits OVER its edge and takes no
 * room. Its own border and ground stand down. */
.popup-focus.popup-focus-turn.popup-focus-ring {
    --pf-bw: 0px;
    border: 0;
    background: transparent;
}

.popup-focus-turn > .pf-sheen {
    position: absolute;
    inset: calc(-1 * var(--pf-bw));
    z-index: 41;
    pointer-events: none;
    container-type: size;
    padding: 1px;
    border-radius: inherit;
    animation: amb-join-dialog-glow 1ms;
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask-composite: exclude;
}

.popup-focus-ring > .pf-sheen {
    background: linear-gradient(to bottom, var(--pf-edge-top), var(--pf-edge-bottom));
}

.popup-focus-turn > .pf-sheen::before {
    content: '';
    position: absolute;
    left: 50%;
    top: 50%;
    width: calc(100cqw + 100cqh);
    height: calc(100cqw + 100cqh);
    margin: calc((100cqw + 100cqh) / -2) 0 0 calc((100cqw + 100cqh) / -2);
    background: conic-gradient(
        from 0deg,
        transparent 0deg,
        transparent 130deg,
        var(--pf-sheen) 180deg,
        transparent 230deg,
        transparent 360deg
    );
    will-change: transform;
    transform: rotate(calc(var(--amb-step, 0) * 15deg));
}

@media (prefers-reduced-motion: reduce) {
    .popup-focus {
        --pf-sheen: transparent;
        animation: none;
    }

    .popup-focus-turn > .pf-sheen::before {
        transform: none;
    }
}

/* ANIMATIONS SETTING (issue #1617): `html[data-motion="off"]` wears the reduced-motion look above, whatever the OS says;
 * the animation itself is stopped by the one rule in animation-pause.css. */
:root[data-motion="off"] .popup-focus {
    --pf-sheen: transparent;
}
