/* virtualpet.css — the virtual pet's dock, its print, its canvas, and the
   flat stand-in. Markup: inc/pet-dock.php. Behaviour: assets/js/virtualpet-toy.js. */

/* ── One number sizes everything ─────────────────────────────────────────
   --pet-k is CSS pixels per world unit. The device is 2.4 × 2.6 units; its
   pad, the strap's headroom, the buttons and the canvas are all multiples of
   it, in CSS here and in the 3D scene alike (the script reads it back from
   the pad's height).

   On a desktop it is 110: the size the first 3D toy was, and the size it
   should stay — bigger than that and it is a gigantic thing in the column.
   On a phone the toy is the thing to touch, so it is a little bigger, and
   gives way to the width of the page when that is the tighter limit. */
.vpet-dock {
    --pet-k: 110px;
    container-type: inline-size;
    position: relative;
    width: 100%;
    /* A finger that sets off up or down from here scrolls the page, as it
       would anywhere; one that sets off sideways is left to the script, which
       takes it for the toy. (virtualpet-toy.js, "A finger on the toy…") */
    touch-action: pan-y pinch-zoom;
}
@media (max-width: 768px) {
    .vpet-dock { --pet-k: 116px; }
}
@supports (width: 1cqw) {
    .vpet-dock { --pet-k: min(100cqw / 2.8, 110px); }
    @media (max-width: 768px) {
        .vpet-dock { --pet-k: min(100cqw / 2.8, 116px); }
    }
}

/* Headroom above the pad for the strap and its bead: 1 K, the strap zone
   and a 10px gutter of paper under it (the dock's print frames the zone as
   a panel of its own; the pad stays exactly 1 K down, where the scene puts
   the toy). */
.vpet-strapzone {
    box-sizing: border-box;
    height: calc(1 * var(--pet-k) - 10px);
    margin-bottom: 10px;
}

/* A finger held on the toy is holding the toy, not selecting the page under
   it or asking for a menu. */
.vpet-strapzone,
.vpet-pad,
.vpet-btn {
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}

/* The pad: the toy's home, and a frame that fits it. */
.vpet-pad {
    position: relative;
    box-sizing: border-box;
    width: 100%;
    height: calc(3.1 * var(--pet-k));
    border: 1px dotted color-mix(in srgb, var(--obi-text) 35%, transparent);
    background-color: color-mix(in srgb, var(--obi-accent) 6%, transparent);
    background-image: repeating-linear-gradient(
        45deg,
        transparent 0,
        transparent 14px,
        color-mix(in srgb, var(--obi-text) 5%, transparent) 14px,
        color-mix(in srgb, var(--obi-text) 5%, transparent) 16px
    );
}

/* ── The dock's print ────────────────────────────────────────────────────
   The strap zone and the pad are two panels printed on the obi's paper,
   the same width, a 10px gutter between them, framed alike: the pad's own
   dotted rule round both, whatever is printed in them. Tints of the obi's
   ink (--obi-text) and accent, the pure accent only in touches (the rule
   the screen's suns follow); no texture of their own, the obi's grain
   shows through. The toy, its strap and its bead lie on the print.

   Two shuffle channels, picked independently by theme-randomizer.js, kept
   by Shift ("keep the art"), carried by the copy-URL:
     data-strap (--strap-sets, ?strap=)  ONE fill for the strap zone, a band
                                         in its frame
     data-pad   (--pad-sets,   ?pad=)    a design for the pad
   With neither (the lab page, or before the script has run) the pad is
   the original above and the strap zone bare paper.

   Straps  asanoha seigaiha kikko shippo   wagara reversed out of a band
           type       VIRTUAL PET set to the band's width
           type-ja    電子ペット the same
           barcode    a barcode across the band, its number in the guards'
                      gaps
           halftone   a dot sky, large at the top
           colorbar   the press's colour strip, in the inks this shuffle
                      loaded
   Pads    asanoha seigaiha kikko shippo   the wash, the pattern drawn
                      faintly where the diagonal was
           halftone   the wash, dots deepening toward the sides
           proof      the wash, a registration target for the landing mark
           diag       the original pad

   The masks are www/assets/img/dock/*.svg, drawn by
   toolbox/virtualpet/tools/dock-print.js; the pad's are centred on the toy
   (the pad's middle), so what shows either side of it is the same. */
.vpet-dock {
    --dock-rule: 1px dotted color-mix(in srgb, var(--obi-text) 35%, transparent);
    --dock-band: color-mix(in srgb, var(--obi-accent) 20%, transparent);
}
.vpet-strapzone {
    position: relative;
    overflow: hidden;
}
.vpet-strapzone::before,
.vpet-strapzone::after,
.vpet-pad::before,
.vpet-pad::after {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

/* Straps ───────────────────────────────────────────────────────────────── */

/* every fill: the strap zone framed and banded like the pad */
:root[data-strap] .vpet-strapzone {
    border: var(--dock-rule);
    background-color: var(--dock-band);
}

/* wagara: the band, the pattern's lines left as paper */
:root[data-strap="asanoha"]  .vpet-strapzone::before { --strap-tile: url(/assets/img/dock/asanoha.svg?v=1) center / 30px 52px repeat; }
:root[data-strap="seigaiha"] .vpet-strapzone::before { --strap-tile: url(/assets/img/dock/seigaiha.svg?v=1) center / 44px 22px repeat; }
:root[data-strap="kikko"]    .vpet-strapzone::before { --strap-tile: url(/assets/img/dock/kikko.svg?v=1) center / 48px 28px repeat; }
:root[data-strap="shippo"]   .vpet-strapzone::before { --strap-tile: url(/assets/img/dock/shippo.svg?v=1) center / 28px 28px repeat; }
:root[data-strap="asanoha"] .vpet-strapzone,
:root[data-strap="seigaiha"] .vpet-strapzone,
:root[data-strap="kikko"] .vpet-strapzone,
:root[data-strap="shippo"] .vpet-strapzone {
    background-color: transparent;
}
:root[data-strap="asanoha"] .vpet-strapzone::before,
:root[data-strap="seigaiha"] .vpet-strapzone::before,
:root[data-strap="kikko"] .vpet-strapzone::before,
:root[data-strap="shippo"] .vpet-strapzone::before {
    content: "";
    background: color-mix(in srgb, var(--obi-accent) 32%, transparent);
    -webkit-mask: var(--strap-tile), linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask: var(--strap-tile), linear-gradient(#000 0 0);
    mask-composite: exclude;
}

/* type: one word set to the band's width inside a 10px margin, centred on
   its height. Line-height 1; from the faces' measured metrics: Sofia Sans
   Extra Condensed 800 — "VIRTUAL PET" 3.928 em wide, capitals .66 em,
   their top .14 em into the line; Kosugi — "電子ペット" 5 em wide, ink .90
   em tall, its top .06 em into the line. */
:root[data-strap="type"] .vpet-strapzone::after,
:root[data-strap="type-ja"] .vpet-strapzone::after {
    right: auto;
    bottom: auto;
    left: 10px;
    font-size: var(--dock-f);
    line-height: 1;
    white-space: pre;
    color: var(--obi-accent);
}
:root[data-strap="type"] .vpet-strapzone::after {
    --dock-f: calc((100cqw - 22px) / 3.928);
    content: "VIRTUAL PET";
    top: calc((var(--pet-k) - 12px) / 2 - var(--dock-f) * .47);
    font-family: "Sofia Sans Extra Condensed", sans-serif;
    font-weight: 800;
}
:root[data-strap="type-ja"] .vpet-strapzone::after {
    --dock-f: calc((100cqw - 22px) / 5);
    content: "電子ペット";
    top: calc((var(--pet-k) - 12px) / 2 - var(--dock-f) * .51);
    font-family: Kosugi, sans-serif;
}

/* barcode: the bars over the band inside a 10px margin, the guards their
   full height; the number in the guards' gaps, twelve digits at seven
   modules each (a module is the barcode's width / 95; the first digit,
   which belongs outside the bars, is left off). Fira Mono 13px: advance
   7.8px; the line's foot 2.1px under the baseline. */
:root[data-strap="barcode"] .vpet-strapzone::before {
    content: "";
    inset: 10px;
    background: color-mix(in srgb, var(--obi-text) 80%, transparent);
    -webkit-mask: url(/assets/img/dock/barcode.svg?v=1) 0 0 / 100% 100% no-repeat;
    mask: url(/assets/img/dock/barcode.svg?v=1) 0 0 / 100% 100% no-repeat;
}
:root[data-strap="barcode"] .vpet-strapzone::after {
    --dock-m: calc((100cqw - 22px) / 95);
    content: "058780 000015";
    top: auto;
    right: auto;
    left: calc(10px + var(--dock-m) * 3 + (var(--dock-m) * 7 - 7.8px) / 2);
    bottom: 9.9px;
    font: 500 13px/1 "Fira Mono", ui-monospace, monospace;
    letter-spacing: calc(var(--dock-m) * 7 - 7.8px);
    word-spacing: calc(var(--dock-m) * -2);
    white-space: pre;
    color: color-mix(in srgb, var(--obi-text) 80%, transparent);
}

/* halftone: a dot tone of its own in the frame, no band under it */
:root[data-strap="halftone"] .vpet-strapzone { background-color: transparent; }
:root[data-strap="halftone"] .vpet-strapzone::before {
    content: "";
    background: color-mix(in srgb, var(--obi-accent) 45%, transparent);
    -webkit-mask: url(/assets/img/dock/dots-sky.svg?v=1) center top / 11px 116px repeat-x;
    mask: url(/assets/img/dock/dots-sky.svg?v=1) center top / 11px 116px repeat-x;
}

/* colorbar: in the band's place, the press's colour strip inside the same
   10px margin, on paper: the accent, the second accent and the ink, each
   solid and in tints. */
:root[data-strap="colorbar"] .vpet-strapzone {
    background: linear-gradient(90deg,
        var(--obi-accent) 0 10%,
        color-mix(in srgb, var(--obi-accent) 70%, transparent) 10% 20%,
        color-mix(in srgb, var(--obi-accent) 40%, transparent) 20% 30%,
        color-mix(in srgb, var(--obi-accent) 15%, transparent) 30% 40%,
        var(--obi-accent-2) 40% 50%,
        color-mix(in srgb, var(--obi-accent-2) 50%, transparent) 50% 60%,
        var(--obi-text) 60% 70%,
        color-mix(in srgb, var(--obi-text) 60%, transparent) 70% 80%,
        color-mix(in srgb, var(--obi-text) 30%, transparent) 80% 90%,
        color-mix(in srgb, var(--obi-text) 10%, transparent) 90% 100%
    ) 10px 10px / calc(100% - 20px) calc(100% - 20px) no-repeat;
}

/* Pads ─────────────────────────────────────────────────────────────────── */

/* wagara: the wash, the pattern drawn faintly where the diagonal was */
:root[data-pad="asanoha"]  .vpet-pad::before { --pad-tile: url(/assets/img/dock/asanoha.svg?v=1) center / 30px 52px repeat; }
:root[data-pad="seigaiha"] .vpet-pad::before { --pad-tile: url(/assets/img/dock/seigaiha.svg?v=1) center / 44px 22px repeat; }
:root[data-pad="kikko"]    .vpet-pad::before { --pad-tile: url(/assets/img/dock/kikko.svg?v=1) center / 48px 28px repeat; }
:root[data-pad="shippo"]   .vpet-pad::before { --pad-tile: url(/assets/img/dock/shippo.svg?v=1) center / 28px 28px repeat; }
:root[data-pad="asanoha"] .vpet-pad::before,
:root[data-pad="seigaiha"] .vpet-pad::before,
:root[data-pad="kikko"] .vpet-pad::before,
:root[data-pad="shippo"] .vpet-pad::before {
    content: "";
    background: color-mix(in srgb, var(--obi-text) 9%, transparent);
    -webkit-mask: var(--pad-tile);
    mask: var(--pad-tile);
}

/* halftone: the wash, dots deepening toward the sides */
:root[data-pad="halftone"] .vpet-pad::before {
    content: "";
    background: color-mix(in srgb, var(--obi-accent) 32%, transparent);
    -webkit-mask: url(/assets/img/dock/dots-pad.svg?v=1) center / 704px 11px repeat-y;
    mask: url(/assets/img/dock/dots-pad.svg?v=1) center / 704px 11px repeat-y;
}

/* proof: the wash, a registration target, the landing mark */
:root[data-pad="proof"] .vpet-pad::before {
    content: "";
    background: color-mix(in srgb, var(--obi-text) 22%, transparent);
    -webkit-mask: url(/assets/img/dock/target.svg?v=1) center / calc(4 * var(--pet-k)) calc(4 * var(--pet-k)) no-repeat;
    mask: url(/assets/img/dock/target.svg?v=1) center / calc(4 * var(--pet-k)) calc(4 * var(--pet-k)) no-repeat;
}

/* each of these replaces the original's diagonal; diag keeps it */
:root[data-pad="asanoha"] .vpet-pad,
:root[data-pad="seigaiha"] .vpet-pad,
:root[data-pad="kikko"] .vpet-pad,
:root[data-pad="shippo"] .vpet-pad,
:root[data-pad="halftone"] .vpet-pad,
:root[data-pad="proof"] .vpet-pad {
    background-image: none;
}

/* ── The 3D toy's canvas ─────────────────────────────────────────────────
   At rest on its pad the canvas sits here, in the page's own flow, so it
   scrolls with the page exactly — nothing tracks it. The moment the toy is
   picked up the canvas moves to .vpet-overlay, above everything, and follows
   the toy around the window. It never takes pointer events itself: the script
   listens at the window and asks the scene what, if anything, was hit, so the
   page underneath stays clickable right up to the toy's outline.

   The canvas is a good deal bigger than the toy (it has to hold the strap at
   full stretch), so at rest it is seen through .vpet-view: a frame the width
   of the column, reaching a little below the pad for the shadow. Without it
   the canvas would hang out past the edge of a narrow page and make the whole
   page scroll sideways. */
.vpet-view {
    position: absolute;
    left: -10px;
    right: -10px;
    top: -10px;
    bottom: calc(-0.7 * var(--pet-k));
    z-index: 1;
    overflow: hidden;
    pointer-events: none;
}
.vpet-slot {
    position: absolute;
    left: 50%;
    top: calc(10px + 2.55 * var(--pet-k));      /* the middle of the pad */
    width: 0;
    height: 0;
}
.vpet-canvas {
    position: absolute;
    left: 0;
    top: 0;
    display: block;
    pointer-events: none;
    user-select: none;
    -webkit-user-select: none;
}
.vpet-overlay {
    position: fixed;
    inset: 0;
    z-index: 150;
    overflow: hidden;
    pointer-events: none;
    contain: strict;
}
html.vpet-grab,     html.vpet-grab *     { cursor: grab !important; }
html.vpet-press,    html.vpet-press *    { cursor: pointer !important; }
html.vpet-grabbing, html.vpet-grabbing * { cursor: grabbing !important; user-select: none !important; -webkit-user-select: none !important; }

/* ── The controls ────────────────────────────────────────────────────────
   Three real buttons. With the 3D toy they are laid, invisible, over the
   toy's own buttons — the script positions them — so keyboard focus lands
   where the eye expects and shows its ring there. Pointers go straight
   through them to the toy. In the flat stand-in they ARE the buttons. */
.vpet-controls {
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    visibility: hidden;
}
.vpet-dock[data-pet-mode] .vpet-controls { visibility: visible; }

.vpet-btn {
    position: absolute;
    left: 50%;
    top: 50%;
    width: calc(0.4 * var(--pet-k));
    height: calc(0.4 * var(--pet-k));
    margin: calc(-0.2 * var(--pet-k)) 0 0 calc(-0.2 * var(--pet-k));
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: transparent;
    font-size: 0;
    appearance: none;
    -webkit-appearance: none;
}
.vpet-btn:focus { outline: none; }
.vpet-btn:focus-visible {
    outline: 2px solid var(--obi-text);
    outline-offset: 4px;
    box-shadow: 0 0 0 6px color-mix(in srgb, var(--obi-bg) 80%, transparent);
}

/* ── The flat stand-in ───────────────────────────────────────────────────
   Shown when there is no WebGL, or the visitor prefers reduced motion. Same
   device, same screen, same proportions, drawn with boxes. It does not move. */
.vpet-flat {
    position: absolute;
    z-index: 1;                 /* over the pad's print (.vpet-pad::after) */
    left: 50%;
    top: 50%;
    width: calc(2.5 * var(--pet-k));
    height: calc(2.7 * var(--pet-k));
    margin: calc(-1.35 * var(--pet-k)) 0 0 calc(-1.25 * var(--pet-k));
}
.vpet-flat[hidden] { display: none; }

.vpet-flat__body {
    position: absolute;
    inset: 0;
    border-radius: calc(0.23 * var(--pet-k));
    background: color-mix(in srgb, var(--obi-surface) 82%, #000);
    box-shadow:
        inset calc(-0.04 * var(--pet-k)) calc(-0.05 * var(--pet-k)) 0 color-mix(in srgb, var(--obi-surface) 62%, #000),
        calc(-0.05 * var(--pet-k)) calc(0.07 * var(--pet-k)) calc(0.16 * var(--pet-k)) rgba(0, 0, 0, 0.28);
}
/* the screen, in its black frame */
.vpet-flat__lens {
    position: absolute;
    left: calc(0.19 * var(--pet-k));
    top: calc(0.19 * var(--pet-k));
    width: calc(2.12 * var(--pet-k));
    height: calc(1.77 * var(--pet-k));
    box-sizing: border-box;
    padding: calc(0.06 * var(--pet-k));
    border-radius: calc(0.05 * var(--pet-k));
    background: #1a1a1a;
}
.vpet-flat__lcd {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    /* the screen's own backing, either side of the dot matrix (virtualpet-lcd.js: the page colour, 5% toward the ink) */
    background: color-mix(in srgb, var(--obi-bg) 95%, var(--obi-text));
}
.vpet-flat__legends { display: none; }

.vpet-flat__post {
    position: absolute;
    left: calc(1.06 * var(--pet-k));
    top: calc(-0.17 * var(--pet-k));
    width: calc(0.38 * var(--pet-k));
    height: calc(0.2 * var(--pet-k));
    border-radius: calc(0.07 * var(--pet-k)) calc(0.07 * var(--pet-k)) 0 0;
    background: var(--acc-700, var(--obi-accent));
}
.vpet-flat__strap {
    position: absolute;
    left: calc(1.2 * var(--pet-k));
    top: calc(-0.98 * var(--pet-k));
    width: calc(1.2 * var(--pet-k));
    height: calc(1 * var(--pet-k));
    overflow: visible;
}
.vpet-flat__strap path   { stroke: var(--obi-text); stroke-width: 7.5; }
.vpet-flat__strap circle { fill: var(--obi-accent); }

/* In the flat stand-in the buttons are visible, and take the pointer: round
   caps in the accent colour, each with its picture. */
.vpet-dock[data-pet-mode="flat"] .vpet-controls { pointer-events: auto; }
.vpet-dock[data-pet-mode="flat"] .vpet-btn {
    /* Lit from beneath, like the 3D toy's: the plastic a touch brighter, and
       its light falling wide and soft on the face round it (never over the
       picture). --vpet-led is set by the script from the theme's tokens. */
    background: color-mix(in srgb, var(--obi-accent) 88%, var(--vpet-led, var(--obi-accent)));
    box-shadow:
        calc(0.03 * var(--pet-k)) calc(0.04 * var(--pet-k)) 0 color-mix(in srgb, var(--obi-accent) 70%, #000),
        0 0 calc(0.45 * var(--pet-k)) calc(0.02 * var(--pet-k)) color-mix(in srgb, var(--vpet-led, transparent) 22%, transparent);
    cursor: pointer;
    touch-action: manipulation;
}
.vpet-dock[data-pet-mode="flat"] .vpet-btn::before {
    content: "";
    position: absolute;
    inset: 20%;
    background: var(--vpet-led, color-mix(in srgb, var(--obi-text) 55%, var(--obi-surface)));
    -webkit-mask: var(--vpet-icon) center / contain no-repeat;
    mask: var(--vpet-icon) center / contain no-repeat;
}
.vpet-btn[data-pet-action="feed"]  { --vpet-icon: url(/assets/icon/burger.svg); }
.vpet-btn[data-pet-action="play"]  { --vpet-icon: url(/assets/icon/game.svg); }
.vpet-btn[data-pet-action="clean"] { --vpet-icon: url(/assets/icon/toilet-paper.svg); }
.vpet-dock[data-pet-mode="flat"] .vpet-btn:active,
.vpet-dock[data-pet-mode="flat"] .vpet-btn.is-down {
    transform: translate(calc(0.02 * var(--pet-k)), calc(0.03 * var(--pet-k)));
    box-shadow: calc(0.01 * var(--pet-k)) calc(0.01 * var(--pet-k)) 0 color-mix(in srgb, var(--obi-accent) 70%, #000);
}
@media (prefers-reduced-motion: no-preference) {
    .vpet-dock[data-pet-mode="flat"] .vpet-btn { transition: transform 0.06s ease-out, box-shadow 0.06s ease-out; }
}
