/* ==================================================================
   Controller — the reticle and the cursor.
   ==================================================================

   Two elements, and no third. There is no legend, no status pill, no
   banner: the pad is an invisible system, and the only thing it draws is
   where you are. See pad/pad.js.

   Both elements are created by JavaScript and only when a controller is
   actually present, so this stylesheet matches nothing at all on the
   overwhelming majority of visits. It is safe to ship on every page.

   Colour comes from the Constellation tokens the rest of the site
   already defines — `--cs-cosmic` for the reticle, `--cs-error` for a
   refusal, `--cs-warning` for a legal target while a card is in hand.
   Fallbacks are written into every var() because the bracket, the radio
   and the home page load different stylesheets and this one must not
   depend on which.
   ================================================================== */

:root {
    --pad-live:    var(--cs-cosmic,  #8edcff);
    --pad-blocked: var(--cs-error,   #e27d86);
    --pad-target:  var(--cs-warning, #e6d89a);
    /* Above everything the site puts up — the sidebar drawer and the
       cookie bar both sit in the 2147483xxx band. The reticle has to be
       over them, because it is what says which of their controls you are
       on. */
    --pad-layer: 2147483300;
}

/* ---------------- the reticle ----------------

   Positioned at the origin and moved with a transform, so travelling
   between two elements is a composited move rather than a layout. The
   size is written to width/height rather than to a scale, because a
   scaled ring would thin its own border as it grew. */
.pad-reticle {
    position: fixed;
    top: 0;
    left: 0;
    z-index: var(--pad-layer);
    pointer-events: none;
    opacity: 0;
    /* Plain values first, color-mix second: a browser without color-mix
       drops the second declaration and keeps a ring that still reads,
       rather than losing its border entirely. The same pattern is used
       everywhere below. */
    border: 1.5px solid var(--pad-live);
    border: 1.5px solid color-mix(in srgb, var(--pad-live) 88%, transparent);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .55), 0 0 14px rgba(142, 220, 255, .34);
    box-shadow:
        0 0 0 1px rgba(0, 0, 0, .55),
        0 0 14px color-mix(in srgb, var(--pad-live) 34%, transparent),
        0 0 38px color-mix(in srgb, var(--pad-live) 16%, transparent);
    transition: opacity 140ms ease, border-color 140ms ease;
}

.pad-reticle.is-on { opacity: 1; }

/* Corner brackets — eight strips, four corners. Drawn on a pseudo rather
   than as extra elements so the ring stays one node, and inset slightly
   outside the border so they read as a frame around the thing rather
   than as decoration on top of it. */
.pad-reticle::before {
    content: '';
    position: absolute;
    inset: -4px;
    --c: var(--pad-live);
    --t: 1.5px;
    --l: 11px;
    background:
        linear-gradient(var(--c), var(--c)) 0    0    / var(--t) var(--l) no-repeat,
        linear-gradient(var(--c), var(--c)) 0    0    / var(--l) var(--t) no-repeat,
        linear-gradient(var(--c), var(--c)) 100% 0    / var(--t) var(--l) no-repeat,
        linear-gradient(var(--c), var(--c)) 100% 0    / var(--l) var(--t) no-repeat,
        linear-gradient(var(--c), var(--c)) 0    100% / var(--t) var(--l) no-repeat,
        linear-gradient(var(--c), var(--c)) 0    100% / var(--l) var(--t) no-repeat,
        linear-gradient(var(--c), var(--c)) 100% 100% / var(--t) var(--l) no-repeat,
        linear-gradient(var(--c), var(--c)) 100% 100% / var(--l) var(--t) no-repeat;
    filter: drop-shadow(0 0 4px rgba(142, 220, 255, .55));
}

/* While a card is in hand, Champ☆Star marks every slot as one that can
   or cannot take it. The reticle reads those marks rather than tracking
   the carry itself, so the ring says whether the slot in front of you is
   free *before* you press A — which dragging can only ever tell you
   afterwards, by refusing. */
.pad-reticle.is-target  { border-color: var(--pad-target); }
.pad-reticle.is-target::before  { --c: var(--pad-target); }
.pad-reticle.is-blocked { border-color: var(--pad-blocked); }
.pad-reticle.is-blocked::before { --c: var(--pad-blocked); }

/* A press, acknowledged. `ok` is a flare outward; `no` is a short
   shudder in place — the same two answers a physical control gives, and
   with no legend on screen they are the whole vocabulary. */
.pad-reticle.pulse-ok  { animation: pad-flare 260ms ease-out; }
.pad-reticle.pulse-no  { animation: pad-shudder 200ms ease-in-out; }

@keyframes pad-flare {
    0%   { box-shadow: 0 0 0 1px rgba(0,0,0,.55),
                       0 0 14px color-mix(in srgb, var(--pad-live) 34%, transparent); }
    35%  { box-shadow: 0 0 0 1px rgba(0,0,0,.55),
                       0 0 4px  color-mix(in srgb, var(--pad-live) 95%, transparent),
                       0 0 34px color-mix(in srgb, var(--pad-live) 60%, transparent),
                       0 0 70px color-mix(in srgb, var(--pad-live) 26%, transparent); }
    100% { box-shadow: 0 0 0 1px rgba(0,0,0,.55),
                       0 0 14px color-mix(in srgb, var(--pad-live) 34%, transparent); }
}

@keyframes pad-shudder {
    0%, 100% { margin-left: 0; }
    25%      { margin-left: -3px; }
    75%      { margin-left: 3px; }
}

/* ---------------- the cursor ----------------

   The fallback, for what focus cannot reach. A ring with a dot in it
   rather than an arrow: an arrow implies the operating system's pointer,
   and this one cannot do everything that pointer can — most visibly it
   cannot produce CSS :hover. Looking like its own thing is more honest
   than looking like a mouse that half works. */
.pad-cursor {
    position: fixed;
    top: 0;
    left: 0;
    z-index: calc(var(--pad-layer) + 1);
    width: 22px;
    height: 22px;
    margin: -11px 0 0 -11px;
    pointer-events: none;
    opacity: 0;
    border-radius: 50%;
    border: 1.5px solid var(--pad-live);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .5), 0 0 12px rgba(142, 220, 255, .4);
    transition: opacity 140ms ease;
}

.pad-cursor.is-on { opacity: 1; }

.pad-cursor::after {
    content: '';
    position: absolute;
    inset: 8px;
    border-radius: 50%;
    background: var(--pad-live);
    box-shadow: 0 0 8px rgba(142, 220, 255, .8);
}

.pad-cursor.is-pressed { animation: pad-click 220ms ease-out; }

@keyframes pad-click {
    30%  { box-shadow: 0 0 0 1px rgba(0,0,0,.5),
                       0 0 0 7px color-mix(in srgb, var(--pad-live) 26%, transparent); }
    100% { box-shadow: 0 0 0 1px rgba(0,0,0,.5),
                       0 0 12px color-mix(in srgb, var(--pad-live) 40%, transparent); }
}

/* The stand-in for :hover. A synthetic event cannot set the real thing —
   that state belongs to the browser's own pointer — so the element under
   the cursor is given this class instead. Deliberately understated: it
   is a hint that the cursor has found something, not an impersonation of
   the site's hover art, which it could never keep up with. */
.pad-cursor-over {
    outline: 1px solid rgba(142, 220, 255, .55);
    outline-offset: 2px;
}

/* ---------------- when the pad is driving ----------------

   The native caret-brown focus ring would sit inside the reticle and say
   the same thing twice, so it is dropped while a pad is live — and only
   then. A keyboard user on the same page keeps every outline they had.
   In cursor mode the reticle is down, so the outline comes back: there
   would otherwise be nothing at all indicating focus. */
body.pad-active:not(.pad-cursor-mode) :focus-visible { outline: none; }

/* ---------------- motion ---------------- */

@media (prefers-reduced-motion: reduce) {
    .pad-reticle,
    .pad-cursor { transition: none; }
    .pad-reticle.pulse-ok,
    .pad-reticle.pulse-no,
    .pad-cursor.is-pressed { animation: none; }
}

/* A viewport this narrow is a phone, and a phone with a controller
   attached is rare enough that it is not worth the ring being drawn over
   a layout it was never measured against. The subsystem keeps working —
   focus still moves, buttons still fire — it simply stops drawing.

   (`hover: none` is not used for this: an Xbox pad on a tablet reports
   exactly that, and it is the case this whole folder exists for.) */
@media (max-width: 480px) {
    .pad-reticle, .pad-cursor { display: none; }
}
