/* Picker page tactile flourishes that the Tailwind utilities alone do not give us.
   Tokens live in base.html under :root / [data-theme]. */

.confetti-piece {
    position: fixed;
    top: -16px;
    width: 10px;
    height: 14px;
    border-radius: 2px;
    pointer-events: none;
    z-index: 9999;
    animation-name: confetti-fall;
    /* Near-linear with a soft start: pieces stay airborne the whole ride
       instead of front-loading the fall into the first second. */
    animation-timing-function: cubic-bezier(0.45, 0.05, 0.6, 0.95);
    animation-fill-mode: forwards;
    transform: rotate(0deg);
}

@keyframes confetti-fall {
    0% {
        transform: translate(0, 0) rotate(0deg);
        opacity: 1;
    }
    82% {
        opacity: 1;
    }
    100% {
        transform: translate(var(--drift, 0vw), 110vh) rotate(var(--spin, 720deg));
        opacity: 0;
    }
}

/* Paper grain on the stage. Two scales of dot fields give a hand-printed read. */
.paper-grain {
    background-image:
        radial-gradient(color-mix(in oklch, var(--ink) 6%, transparent) 1px, transparent 1px),
        radial-gradient(color-mix(in oklch, var(--ink) 4%, transparent) 1px, transparent 1px);
    background-size: 6px 6px, 9px 9px;
    background-position: 0 0, 3px 3px;
}

.stage-canvas {
    width: 100%;
    height: 360px;
    max-height: min(60vh, 480px);
    display: block;
}

@media (min-width: 768px) {
    .stage-canvas {
        height: 480px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .confetti-piece {
        display: none;
    }
}

/* CSS 3D dice. Real perspective cube; faces are DOM nodes so the
   text stays crisp at any rotation. */
.dice-scene {
    position: relative;
    /* Strong, centered perspective so the dice visually rotates around its
       own center. The previous 50% 45% perspective-origin made the camera
       look slightly downward, which biased the rendered silhouette upward
       as the polyhedron rotated — that's what was reading as "rotating
       around a point in space" instead of around the dice itself.
       A larger perspective distance also flattens the asymmetry between
       front- and back-facing vertices. */
    perspective: 2400px;
    perspective-origin: 50% 50%;
}

/* Anchor: a fixed-size circular viewport at the scene's center. The cube
   rotates inside; everything outside the circle is clipped. The visible
   boundary is always a fixed circle — the dice can never APPEAR to
   translate even when its underlying silhouette is asymmetric. */
/* Dice mode now renders via three.js (WebGL) into a canvas that fills
   the stage. CSS-3D anchor/cube/face rules below are kept only for the
   d2 (card flip) and d6 (cube) preview fallbacks; everything else is
   handled inside dice.js. */

.dice-scene::before {
    content: '';
    position: absolute;
    bottom: 16%;
    left: 50%;
    width: 200px;
    height: 26px;
    transform: translateX(-50%);
    background: radial-gradient(ellipse at center, color-mix(in oklch, var(--ink) 35%, transparent) 0%, transparent 65%);
    filter: blur(6px);
    pointer-events: none;
}

.dice-cube {
    --size: 140px;
    width: var(--size);
    height: var(--size);
    /* Centered inside the .dice-anchor (which is now a 280x280 circular
       viewport). 50%, 50% with translate(-50%, -50%) puts the cube's center
       at the anchor's center; the matrix3d injected by JS rotates around
       that center. */
    position: absolute;
    left: 50%;
    top: 50%;
    transform-style: preserve-3d;
    transform-origin: 50% 50% 0;
    transform: translate(-50%, -50%) rotateX(-25deg) rotateY(35deg);
    will-change: transform;
}

.dice-face {
    position: absolute;
    inset: 0;
    background: var(--surface-1);
    border: 1.5px solid var(--ink);
    border-radius: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: -apple-system, BlinkMacSystemFont, Inter, system-ui, sans-serif;
    font-weight: 900;
    font-size: clamp(14px, calc(var(--size) * 0.20), 30px);
    color: var(--ink);
    backface-visibility: hidden;
    box-shadow:
        inset 0 1px 0 color-mix(in oklch, var(--surface-0) 70%, transparent),
        inset 0 -10px 16px color-mix(in oklch, var(--ink) 5%, transparent);
    overflow: hidden;
    padding: 0 10px;
    text-align: center;
    line-height: 1;
    word-break: break-word;
}

.dice-face-front  { transform: translateZ(calc(var(--size) / 2)); }
.dice-face-back   { transform: rotateY(180deg) translateZ(calc(var(--size) / 2)); }
.dice-face-right  { transform: rotateY(90deg)  translateZ(calc(var(--size) / 2)); }
.dice-face-left   { transform: rotateY(-90deg) translateZ(calc(var(--size) / 2)); }
.dice-face-top    { transform: rotateX(90deg)  translateZ(calc(var(--size) / 2)); }
.dice-face-bottom { transform: rotateX(-90deg) translateZ(calc(var(--size) / 2)); }

.dice-face.is-winner {
    background: var(--accent);
    color: var(--accent-ink);
    border-color: var(--ink);
    box-shadow:
        inset 0 1px 0 color-mix(in oklch, var(--accent-ink) 50%, transparent),
        0 0 28px 6px color-mix(in oklch, var(--accent) 50%, transparent);
}

/* d2 card flip. Two faces, no thickness, slightly tall card aspect. */
.dice-d2 {
    --card-w: 130px;
    --card-h: 180px;
    width: var(--card-w);
    height: var(--card-h);
}

.dice-d2 .dice-face {
    width: var(--card-w);
    height: var(--card-h);
    inset: 0;
    border-radius: 14px;
    font-size: clamp(16px, calc(var(--card-w) * 0.20), 30px);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    word-break: keep-all;
}

.dice-d2 .dice-face-front { transform: translateZ(2px); }
.dice-d2 .dice-face-back  { transform: rotateY(180deg) translateZ(2px); }

/* Polyhedra (d4, d8, d12, d20) rendered as a parent cube with face divs
   whose transforms are computed in JS and applied inline. */
.dice-d4, .dice-d8, .dice-d12, .dice-d20 {
    --size: 200px;
    width: var(--size);
    height: var(--size);
}

/* Mouse drag affordance */
.dice-scene {
    cursor: grab;
    touch-action: none;
    user-select: none;
    /* Block native HTML5 drag-and-drop on the scene and everything inside.
       Safari otherwise picks up the inline SVG faces and starts a native
       image-drag in parallel with our pointer handler, dragging the dice
       across the stage. */
    -webkit-user-drag: none;
}
.dice-scene * {
    -webkit-user-drag: none;
    user-drag: none;
}
.dice-scene.is-dragging {
    cursor: grabbing;
}
.dice-cube {
    pointer-events: none;
}

.dice-d4 .dice-face-tri,
.dice-d8 .dice-face-tri,
.dice-d12 .dice-face-pent,
.dice-d20 .dice-face-tri {
    width: var(--face-size, 130px);
    height: var(--face-size, 130px);
    margin-left: calc(var(--face-size, 130px) / -2);
    margin-top: calc(var(--face-size, 130px) / -2);
    left: 50%;
    top: 50%;
    inset: auto;
    background: transparent;
    border: none;
    box-shadow: none;
    padding: 0;
    display: block;
    overflow: visible;
}

.dice-d8 .dice-face-tri svg,
.dice-d12 .dice-face-pent svg,
.dice-d20 .dice-face-tri svg {
    width: 100%;
    height: 100%;
    display: block;
    overflow: visible;
}

.dice-d8 .dice-face-tri.is-winner polygon,
.dice-d12 .dice-face-pent.is-winner polygon,
.dice-d20 .dice-face-tri.is-winner polygon {
    fill: var(--accent);
    stroke: var(--ink);
    filter: drop-shadow(0 0 14px color-mix(in oklch, var(--accent) 55%, transparent));
}

.dice-d8 .dice-face-tri.is-winner text,
.dice-d12 .dice-face-pent.is-winner text,
.dice-d20 .dice-face-tri.is-winner text {
    fill: var(--accent-ink);
}
