/* 3D card component (card3d.js) — ported from the card-foil-lab
   experiment (docs/design/card-foil-lab.html). All class names are
   c3d-prefixed so they can't collide with the viewer's own .chip etc.
   Gotchas learned there and preserved here: CSS image masks read the
   ALPHA channel; never overflow:hidden + border-radius on 3D-rotated
   faces (Chrome clips in the wrong space); corners stay square — a
   physical card is a sharp rectangle. */

.c3d-wrap { display: flex; flex-direction: column; align-items: center; gap: 16px; }

.c3d-scene {
  perspective: 1300px; touch-action: none; cursor: grab;
  user-select: none; -webkit-user-select: none;
  padding: 26px 40px;   /* room so tilted corners don't clip on hover */
}
.c3d-scene:active { cursor: grabbing; }
.c3d-scene:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: var(--radius); }

.c3d-card {
  --ct: 5px;  /* card-stock thickness; ~1.8x true 20pt scale so it reads */
  position: relative; width: min(340px, 62vw); aspect-ratio: 5/7;
  transform-style: preserve-3d; will-change: transform;
  transition: transform .12s ease-out;
}
.c3d-card.c3d-flipping { transition: transform .55s cubic-bezier(.4, .1, .2, 1); }

.c3d-face {
  position: absolute; inset: 0;
  backface-visibility: hidden; -webkit-backface-visibility: hidden;
  box-shadow: 0 24px 60px -18px rgba(0, 0, 0, .85), 0 4px 14px rgba(0, 0, 0, .5);
  background: #000;
  transform: translateZ(calc(var(--ct) / 2));
}
.c3d-face.c3d-back { transform: rotateY(180deg) translateZ(calc(var(--ct) / 2)); }

/* the four cut edges of the card stock: layered paper, lighter at the core */
.c3d-edge { position: absolute; background: #e7e2d8; }
.c3d-edge.c3d-n, .c3d-edge.c3d-s {
  left: 0; width: 100%; height: var(--ct);
  background: linear-gradient(to bottom, #c8c2b6, #f2eee5 45%, #ede8dd 55%, #c3bdb1);
}
.c3d-edge.c3d-w, .c3d-edge.c3d-e {
  top: 0; width: var(--ct); height: 100%;
  background: linear-gradient(to right, #c8c2b6, #f2eee5 45%, #ede8dd 55%, #c3bdb1);
}
.c3d-edge.c3d-n { top: 0;    transform-origin: center top;    transform: translateZ(calc(var(--ct) / -2)) rotateX(90deg); }
.c3d-edge.c3d-s { bottom: 0; transform-origin: center bottom; transform: translateZ(calc(var(--ct) / -2)) rotateX(-90deg); }
.c3d-edge.c3d-w { left: 0;   transform-origin: left center;   transform: translateZ(calc(var(--ct) / 2))  rotateY(90deg); }
.c3d-edge.c3d-e { right: 0;  transform-origin: right center;  transform: translateZ(calc(var(--ct) / 2))  rotateY(-90deg); }

.c3d-face img {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  pointer-events: none; -webkit-user-drag: none;
}
.c3d-layer { position: absolute; inset: 0; pointer-events: none; }

/* The light is FIXED — a soft lamp above the card. Nothing follows the
   pointer; the gloss/rainbow/glitter layers move only with the card's
   rotation (--gp/--gt/--ghue/--gsx/--gsy set in render()). */
.c3d-sheen {
  background: radial-gradient(560px 560px at 50% 18%,
    rgba(255, 255, 255, .26) 0%, rgba(120, 180, 255, .08) 34%, transparent 62%);
  mix-blend-mode: screen; opacity: .5;
}
.c3d-back .c3d-sheen { opacity: .45; }
.c3d-rainbow {
  background: linear-gradient(115deg,
    rgba(255, 60, 60, .35), rgba(255, 190, 40, .35), rgba(80, 255, 120, .32),
    rgba(60, 160, 255, .35), rgba(190, 80, 255, .35));
  background-size: 280% 280%;
  background-position: calc(var(--gp, 50%) * 1.6) calc(var(--gt, 50%) * 1.6);
  mix-blend-mode: color-dodge; opacity: .38;
}
.c3d-glitter {
  background-size: 74px 74px;
  mix-blend-mode: screen; opacity: .5;
  transform: translate(var(--gsx, 0px), var(--gsy, 0px));
}
/* Angular gloss: the card's reflective coating. A narrow specular band
   (white core, iridescent fringes) whose position and hue are driven by
   the CARD'S ROTATION (--gp/--gt/--ghue set in render()), so the
   reflection travels across the surface as the card turns — that
   angle-dependence is what makes it read as a glossy surface instead of
   a printed-on rainbow. Unmasked on purpose: the whole card is coated,
   not just the foil. */
.c3d-gloss {
  /* normal compositing, not screen: the iridescence is a thin-film
     effect that shows on white card stock too — screen-blended light
     vanishes on white and the back would lose its shimmer */
  background: linear-gradient(105deg,
    transparent 38%,
    rgba(255, 255, 255, .14) 45%,
    rgba(255, 120, 200, .13) 48%,
    rgba(140, 255, 220, .13) 52%,
    rgba(120, 170, 255, .13) 55%,
    rgba(255, 255, 255, .14) 58%,
    transparent 65%);
  background-size: 300% 300%;
  background-position: var(--gp, 50%) var(--gt, 50%);
  filter: hue-rotate(var(--ghue, 0deg));
  opacity: .55;
}
/* the back face is rotated 180°, which mirrors its local x-axis — flip
   the band's position so the reflection moves the same screen direction
   on both faces */
.c3d-back .c3d-gloss { background-position: calc(100% - var(--gp, 50%)) var(--gt, 50%); }

.c3d-hint { font-size: 12px; color: var(--text-dim); }
.c3d-hint kbd { font-family: inherit; color: var(--text); }

.c3d-chips { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; max-width: 680px; }
.c3d-chip {
  display: flex; align-items: center; gap: 8px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 999px;
  color: var(--text); font: 13px/1 inherit;
  padding: 7px 12px 7px 8px; cursor: pointer;
}
.c3d-chip:hover { border-color: var(--text-dim); }
.c3d-chip:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.c3d-chip.c3d-on {
  border-color: var(--chip, #fff);
  box-shadow: 0 0 0 1px var(--chip, #fff), 0 0 18px -6px var(--chip, #fff);
}
.c3d-sw {
  width: 15px; height: 15px; border-radius: 50%; background: var(--chip, #999);
  background-image: linear-gradient(135deg, rgba(255, 255, 255, .55), transparent 55%);
}
.c3d-pr {
  font-family: ui-monospace, Consolas, monospace;
  font-variant-numeric: tabular-nums; font-size: 11px; color: var(--text-dim);
}

/* ---- manage strip under the card (seed page) ---------------------- */
.c3d-manage { display: flex; flex-direction: column; gap: 10px; align-items: center; margin-top: 4px; }
.c3d-manage .row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; justify-content: center; }
.c3d-manage label.file {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px; border: 1px dashed var(--border); border-radius: var(--radius);
  color: var(--text-dim); font-size: 12px; cursor: pointer;
}
.c3d-manage label.file:hover { border-color: var(--text-dim); color: var(--text); }
.c3d-manage label.file.set { border-style: solid; border-color: var(--accent-border); color: var(--text); }
.c3d-manage input[type="file"] { display: none; }
.c3d-manage .log {
  font-family: ui-monospace, Consolas, monospace; font-size: 11px;
  color: var(--text-dim); white-space: pre-wrap; max-width: 640px;
  max-height: 130px; overflow-y: auto;
}
