/* ===================================================================
   code-input.css — the slot-by-slot code field.

   One box per character, the typed character rolls up into its box
   behind a caret that slides from slot to slot. Used on /watch, where
   the whole job of the page is "type the five digits off the host's
   panel".

   Two audiences share this control and they pull in opposite
   directions. A phone taps a slot and gets a number pad. A TV drives
   it with a d-pad, so the focused box has to be obvious from ten feet
   away — hence :focus and not :focus-visible, the same call the rest
   of watch.html already makes: remote navigation does not reliably
   register as keyboard input, so :focus-visible can stay dark on the
   one box the viewer is aiming at.

   The slots are real <input>s, not divs. That is what gets a phone its
   number pad, its paste menu, and the SMS autofill — and what lets the
   whole row be walked by a d-pad without a single custom key handler
   for focus.

   Motion lives in code-input.js (the spring is sampled, not eased);
   what is here is everything a still frame shows.
   =================================================================== */

.pp-code {
    --pp-slot: clamp(46px, 9vmin, 68px);
    --pp-gap: clamp(6px, 1.2vmin, 12px);

    position: relative;
    display: flex;
    align-items: center;
    gap: var(--pp-gap);
    flex: 0 1 auto;
}

/* A legacy 8-character code is 60% wider than the five it replaced, so
   the row buys the room back out of the SLOTS rather than out of the
   layout. Same reason the join card still accepts them at all: a code
   somebody wrote down last month must not bounce off this page.
   The eight-slot numbers are cut so the row still sits on ONE line beside
   the address and the Go button at the card's full width — eight slots at
   the six-slot size overflow by a few pixels and drop Go onto a line of
   its own, which is the exact "stray half-width button" this page's own
   phone breakpoint exists to avoid. */
.pp-code[data-len="6"] { --pp-slot: clamp(40px, 7.6vmin, 58px); --pp-gap: clamp(6px, 1.1vmin, 11px); }
.pp-code[data-len="7"] { --pp-slot: clamp(36px, 6.8vmin, 52px); --pp-gap: clamp(5px, 1vmin, 10px); }
.pp-code[data-len="8"] { --pp-slot: clamp(32px, 6vmin, 48px); --pp-gap: clamp(5px, 1vmin, 9px); }

.pp-code__cell {
    position: relative;
    flex: none;
}

.pp-code__slot {
    display: block;
    width: var(--pp-slot);
    height: var(--pp-slot);
    padding: 0;
    text-align: center;

    /* The native glyph is never shown — the animated span in .pp-code__chars
       is. Two copies of the same character on top of each other is exactly
       what a mid-roll frame would look like. */
    color: transparent;
    caret-color: transparent;
    font-family: 'SF Mono', ui-monospace, Menlo, Consolas, monospace;
    font-size: calc(var(--pp-slot) * 0.44);
    font-weight: 700;

    background: var(--color-surface-raised);
    border: 2px solid var(--color-border-hover);
    border-radius: var(--radius-md);
    outline: none;
    -webkit-appearance: none;
    appearance: none;
    transition: border-color 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
}
.pp-code__slot::selection { background: transparent; }
.pp-code__slot::-moz-selection { background: transparent; }

/* --pp-accent is set by whatever this row sits in, so the ring, the caret
   and the card's own icon are one colour. Falls back to the site blue when
   nobody set one. */
.pp-code__slot:focus {
    border-color: var(--pp-accent, var(--color-primary));
    box-shadow: 0 0 0 4px var(--pp-accent-glow, var(--color-primary-glow));
}
.pp-code__cell[data-filled="true"] .pp-code__slot {
    background: var(--color-surface-hover);
    border-color: rgba(255, 255, 255, 0.18);
}

/* ── the character ─────────────────────────────────────────────────
   Clipped to the box, so a character rolling in from below and the one
   it replaces leaving through the top are both invisible until they are
   inside the slot. */
.pp-code__chars {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    overflow: hidden;
    border-radius: var(--radius-md);
    pointer-events: none;
}
.pp-code__char {
    grid-area: 1 / 1;
    font-family: 'SF Mono', ui-monospace, Menlo, Consolas, monospace;
    font-size: calc(var(--pp-slot) * 0.44);
    font-weight: 700;
    line-height: 1;
    color: var(--color-text);
}

/* ── the caret ─────────────────────────────────────────────────────
   ONE caret for the whole row, not one per slot: it is the thing that
   travels, and a per-slot caret appearing and disappearing reads as a
   flicker rather than as a cursor moving. */
.pp-code__caret {
    position: absolute;
    left: 0;
    top: 50%;
    width: 2px;
    height: calc(var(--pp-slot) * 0.42);
    border-radius: 2px;
    background: var(--pp-accent, var(--color-text));
    pointer-events: none;
    transform: translate(-1px, -50%);
    transition: transform 0.22s cubic-bezier(0.2, 0.9, 0.25, 1);
    animation: pp-code-blink 1.1s steps(1, end) infinite;
}
.pp-code__caret[hidden] { display: none; }

@keyframes pp-code-blink {
      0%, 49.99% { opacity: 1; }
    50%,    100% { opacity: 0; }
}

/* ── feedback ──────────────────────────────────────────────────────
   Success is traced in SVG per box (js drives the dash), so there is no
   ring here for it. Error is a plain ring plus one shake of the row. */
.pp-code__ring {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
}
.pp-code[data-status="success"] .pp-code__ring { opacity: 1; }

.pp-code[data-status="error"] .pp-code__slot {
    border-color: var(--color-red);
    box-shadow: 0 0 0 3px rgba(224, 96, 96, 0.22);
    transition-delay: 0.15s;
}
.pp-code[data-status="error"] .pp-code__char { color: var(--color-red); }

@media (prefers-reduced-motion: reduce) {
    .pp-code__caret {
        transition: none;
        animation: none;
        opacity: 1;
    }
}

/* On a phone the address, the row and the button are already three lines,
   so the row owns the full width — and DIVIDES it rather than being sized
   in vw. A vw size has to be re-guessed for every slot count, and the
   eight-slot guess overflowed the card it sits in by 7px at 375. Flex
   cells with a square aspect-ratio fit any count at any width, which is
   also the only reason there is no per-count rule down here. */
@media (max-width: 560px) {
    .pp-code,
    .pp-code[data-len="6"],
    .pp-code[data-len="7"],
    .pp-code[data-len="8"] {
        --pp-gap: clamp(4px, 1.6vw, 10px);
        flex: 1 1 100%;
        width: 100%;
        justify-content: center;
    }
    .pp-code__cell { flex: 1 1 0; min-width: 0; max-width: 62px; }
    .pp-code__slot {
        width: 100%;
        height: auto;
        aspect-ratio: 1;
        font-size: min(6.5vw, 27px);
    }
    .pp-code__char { font-size: min(6.5vw, 27px); }
    .pp-code__caret { height: min(7.5vw, 30px); }
}
