/* ==========================================================================
   Design tokens.

   Everything the overlay system draws with is declared here once. An overlay
   that restates a colour, radius, or duration is a value that will drift the
   first time one of them changes.

   The per-server palettes stay where they are, in index.html: data-server is set
   before first paint by the boot script, and splitting the palette away from the
   rule that reads it would put two files between a server and its colour.
   ========================================================================== */

:root {
    /* --- Surfaces -----------------------------------------------------------
       Three tiers, and the distinction is what an element sits ON, not how
       important it is. --bg is the page. --surface is anything raised off it:
       a card, a dialog, a tray. --surface-2 is raised again, for a control
       sitting on a surface — a tray button against the tray it is in, which
       would otherwise be the same colour as its own background. */
    --bg: #1a1a1a;
    --surface: #2a2a2a;
    --surface-2: #333;
    --border: #3a3f47;
    --border-strong: #474c55;

    /* --- Text --- */
    --text: #fff;
    --muted: #aaa;

    /* --- Backdrop -----------------------------------------------------------
       Dimmed AND blurred, not merely dimmed. Dimming alone leaves the library
       legible behind an overlay and it goes on competing for attention; the
       blur pushes it back to texture while still showing the user where they
       were. */
    --backdrop-tint: rgba(0, 0, 0, 0.55);
    --backdrop-blur: blur(6px);

    /* --- Overlay metrics ----------------------------------------------------
       THERE ARE NO GRIP METRICS HERE, AND THERE WERE TWO. `--grip-height` and
       `--grip-clear` described the distance over which the detail overlay's
       artwork faded itself out so the grab handle never sat on a picture. That
       fade is gone: the handle now clears 3:1 by its own colour, over artwork
       and over bare surface alike, which is stated once at .sheet__handle in
       overlays.css and holds for every tray rather than for the one overlay
       that had a background to remove.

       They are deleted rather than left declared because nothing reads them,
       and a token with no reader is the shape of dead code this project has
       shipped before — it looks like a live decision to everyone who finds it.
       Re-adding the mask therefore has to re-add these too, which is the point:
       tests/test_overlay_layering.py fails if either name reappears under
       web/. */

    /* --- The rhythm inside an overlay's body -------------------------------
       ONE break value for a body that has more than one block in it: the gap
       between two sections, and the gap below the division under a pinned
       region. A heading stands HALF this distance from the block it introduces,
       written as a calc() at the rule rather than as a second token here.

       That half is the whole decision. Proximity is what says a heading belongs
       to the block beneath it, so the gap above a heading must be the larger
       one; when the smaller gap is above, every heading reads as a footer for
       the section before it. The detail overlay's body was exactly that — 5px
       above a heading against 15px below — and it read as one undifferentiated
       column with the headings in the wrong places.

       A token and not two literals because two rules in two files have to agree
       about it: `.modal__fixed + .modal__body` in overlays.css and
       `.modal-section + .modal-section` in index.html. That is the condition
       this file exists for. And a token rather than a second `--…-heading-gap`
       beside it because a value that can be edited on its own is how the
       relation gets broken quietly — the same reasoning that keeps the 992px
       affordance pair in one media query.

       There is no spacing SCALE here, deliberately. One value has two readers;
       a --space-1..6 ramp would be five tokens with none, which is the shape of
       dead code the block above was deleted for. */
    --overlay-section-gap: 24px;

    /* --- Radii --- */
    --radius-sm: 6px;
    --radius-md: 10px;
    --radius-lg: 14px;
    --radius-xl: 20px;
    --radius-pill: 999px;

    /* --- Elevation --- */
    --elev-2: 0 2px 4px rgba(0, 0, 0, 0.2);
    --elev-4: 0 8px 24px rgba(0, 0, 0, 0.4);

    /* --- Motion -------------------------------------------------------------
       Exits are shorter than entrances. Leaving should feel quicker than
       arriving — an overlay the user has dismissed is already gone as far as
       they are concerned, and making them watch it leave is friction.

       --dur-slow is for a tray, which travels the height of its own panel
       rather than the 4% a dialog scales; at --dur-base that distance reads as
       a snap rather than a slide.

       --dur-tab is the same 280ms and deliberately its own name rather than a
       second use of --dur-slow: a tab crosses the full width of the viewport,
       which is a different distance from a tray's own height and will not stay
       tied to it. They agree today because the app should feel like one thing,
       not because one is defined as the other.

       index.html reads --dur-tab back to time the transition's safety teardown,
       so it is the single source for that number in both files. */
    --dur-base: 200ms;
    --dur-slow: 280ms;
    --dur-tab: 280ms;
    --dur-exit: 150ms;
    --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-entrance: cubic-bezier(0, 0, 0.2, 1);
    --ease-exit: cubic-bezier(0.4, 0, 1, 1);

    /* --- The tab drag -------------------------------------------------------
       A swipe between tabs follows the finger. These are the numbers that
       describe that gesture, and they are here rather than in index.html for
       the same reason every other duration is: two files have to agree about
       them. The gesture code reads them back to decide how long a release takes
       to settle.

       THERE IS NO PARALLAX RATIO, and there was one. The incoming tab used to
       enter at a third of the outgoing tab's speed, parked a third of a viewport
       out. That is what iOS does, and here it was wrong: at a third of a
       viewport the two grids OVERLAP for the whole gesture, and which one is on
       top is then decided by document order rather than by direction — so
       TV Shows painted over Movies whichever way the thumb went. The tabs move
       together now, a full viewport apart, edge to edge: one leaves as the other
       arrives, and neither is ever over the other. A ratio fixed at 1 would be a
       knob that does nothing, so it is gone rather than set.

       --dur-tab-settle-min is the floor under a release. The settle's duration
       scales with the distance still to travel, so a tab released at 95% would
       otherwise finish in a few milliseconds and read as a snap rather than as
       the end of a movement. --dur-tab remains the ceiling: a committed swipe
       that barely moved takes exactly as long as the transition did before this
       gesture existed.

       THERE IS NO LIFT TOKEN, AND THAT IS THE THIRD ONE MISSING HERE. A drag
       moves the tabs sideways and does nothing else to them: no scale, no
       scrim, no elevation, no radius. All four were tried and all four are
       gone, so there is nothing left for this block to describe but the
       durations above.

       The scale is the one that shipped, at 0.94, and it was received as the
       grid dropping — anchored to the viewport's midpoint, it pulled everything
       above that midpoint down by ~23px the instant the gesture was claimed.
       The scrim went with it because it had nowhere left to render. The shadow
       and the radius never shipped: these panels are as tall as the whole
       library, so a shadow renders only as a blurred band down each vertical
       edge tracking the thumb, and a radius renders nothing whatsoever.

       index.html says all of this at the rule itself; this is the other half of
       that note, for whoever comes here to add a token back. */
    --dur-tab-settle-min: 120ms;

    /* --- Layering -----------------------------------------------------------
       One ordered scale, not a set of independently chosen numbers.

       A dialog must outrank a tray because a dialog can be raised from inside
       one — the trailer opens from the detail tray — and a dialog rendered
       behind the tray that raised it cannot be used. Page chrome takes the
       lowest tier because it only has to cover the grid, and every overlay must
       cover it. */
    --z-chrome: 30;
    --z-sheet: 50;
    --z-modal: 55;
}

/* Alpine has not initialised yet. Without this every overlay renders expanded
   for a frame before x-show hides it — all six at once, stacked, on first
   paint. */
[x-cloak] {
    display: none !important;
}

/* Reduced motion, stated once and app-wide.

   An overlay moves the largest area of the screen of anything here, so this is
   the most consequential place to miss it. Not `animation: none`: the
   transitions still have to RUN, because Alpine waits for them to finish before
   it removes the element. Zero duration ends them on the next frame, which is
   what "instant" means without stranding an overlay that never fires its
   transitionend. */
@media (prefers-reduced-motion: reduce) {

    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}
