/* ============================================================
   characters.css - the resident duo (にゅるち + ぴよち),
                    their idle motion, poke reaction and bubbles
   ============================================================ */

/* Everything is driven by --ny-w (にゅるち's width, set in base.css).
   Both characters and their relative offsets derive from it, so the whole
   composition scales as one unit and the overlap never drifts.
   --ny-w is measured off the viewport HEIGHT: 86vh makes the cropped upper
   body run about 105vh tall, so it fills from the top of the screen right
   off the bottom edge, and a narrower window no longer shrinks the pair.
   The 72vw term is only a backstop for near-square windows, where a purely
   height-driven figure would run off both sides at once. */
.duo-wrap{
  --py-w: calc(var(--ny-w) * 0.57);

  /* half the rendered height of にゅるち, in --ny-w units (686/564 / 2),
     used to centre the figure on the rail */
  --ny-half: calc(var(--ny-w) * -0.608);
  /* nudge the whole group down so the head clears the top edge */
  --duo-shift: 4vh;
  /* where ぴよち sits, measured down from にゅるち's own top edge */
  --py-drop: 0.56;

  /* a zero-height rail pinned to the LEFT edge at mid height: the group is
     anchored left-centre, so it stays put on the left and grows evenly up
     and down as the window changes shape.
     The offset sits the duo roughly centred in the space between the left
     curtain and the info panel, rather than jammed against the edge. */
  position:absolute;
  left:var(--duo-left);
  top:50%;
  transform:translateY(-50%);
  width:var(--ny-w);
  height:0;
  z-index:var(--z-character);
}

/* every figure hangs from the rail's left-centre origin */
.char-block{ position:absolute; }

.char-block.nyuruchi{
  left:0;
  top:calc(var(--ny-half) + var(--duo-shift));
  width:var(--ny-w);
  z-index:2;
}

/* ぴよち stands in front, overlapping にゅるち's torso by ~46% */
.char-block.piyochi{
  left:calc(var(--ny-w) * 0.54);
  top:calc(var(--ny-half) + var(--ny-w) * var(--py-drop) + var(--duo-shift));
  width:var(--py-w);
  z-index:3;
}

.character-img{
  display:block;
  width:100%;
  height:auto;
  cursor:pointer;
  filter:drop-shadow(0 18px 22px rgba(0,0,0,0.5));
  animation:float 3.6s ease-in-out infinite;
  transform-origin:center bottom;
}

/* にゅるち uses a pre-cropped upper-body image; this dissolves its lower
   edge into the stage so the crop never reads as a hard straight cut. */
.char-block.nyuruchi .character-img{
  -webkit-mask-image:linear-gradient(to bottom, #000 86%, rgba(0,0,0,0) 100%);
  mask-image:linear-gradient(to bottom, #000 86%, rgba(0,0,0,0) 100%);
}

/* offset so the two never bob in sync */
.char-block.piyochi .character-img{ animation-delay:-1.3s; }

/* ---------- motion ---------- */
@keyframes float{
  0%,100%{ transform:translateY(0)      rotate(-1.5deg); }
  50%    { transform:translateY(-2.2%)  rotate(1.5deg); }
}

/* squash-and-stretch reaction, added by js/characters.js on click */
.character-img.poke{ animation:poke 0.55s ease; }

@keyframes poke{
  0%  { transform:scale(1,1); }
  30% { transform:scale(1.08,0.9)  rotate(-3deg); }
  55% { transform:scale(0.95,1.08) rotate(3deg); }
  75% { transform:scale(1.04,0.97) rotate(-1.5deg); }
  100%{ transform:scale(1,1)       rotate(0); }
}

/* ---------- "tap me" nudge ---------- */
/* Hung off the rail, centred under the pair and low on the stage floor.
   (position:fixed would be resolved against .duo-wrap here, not the
   viewport, because the rail carries a transform - hence absolute.) */
.click-hint{
  position:absolute;
  left:calc(var(--ny-w) * 0.45);
  top:36vh;
  transform:translateX(-50%);
  z-index:4;                    /* over both figures, not behind them */
  font-size:clamp(9px,1vw,11px);
  background:rgba(0,0,0,0.5);
  border:1px solid rgba(255,216,115,0.5);
  padding:0.3em 0.8em;
  border-radius:999px;
  opacity:0.85;
  white-space:nowrap;
  animation:pulse 2.2s ease-in-out infinite;
}

@keyframes pulse{
  0%,100%{ opacity:.5; }
  50%    { opacity:.95; }
}

/* ---------- speech bubbles ---------- */
/* Each block is bottom-anchored and taller than the viewport, so a bubble
   placed above a block would land off-screen. They are positioned against
   the block's own top edge (which sits at head height) instead. */
.speech-bubble{
  position:absolute;
  top:-6vh;
  left:50%;
  transform:translate(-50%,10px) scale(0.85);
  min-width:150px;
  max-width:min(38vw,280px);
  background:#fff8ec;
  color:var(--ink);
  border:2px solid var(--gold-deep);
  border-radius:20px;
  padding:0.8em 1.1em;
  font-size:clamp(11px,1.2vw,14px);
  line-height:1.55;
  font-weight:700;
  box-shadow:0 10px 24px rgba(0,0,0,0.35);
  opacity:0;
  pointer-events:none;
  transition:opacity .22s ease, transform .22s ease;
  z-index:var(--z-bubble);
}

.speech-bubble.show{
  opacity:1;
  transform:translate(-50%,0) scale(1);
}

/* tail: border layer then fill layer, one pixel apart */
.speech-bubble::after{
  content:'';
  position:absolute;
  left:50%;
  bottom:-14px;
  transform:translateX(-50%);
  border:8px solid transparent;
  border-top-color:var(--gold-deep);
}

.speech-bubble::before{
  content:'';
  position:absolute;
  left:50%;
  bottom:-10.5px;
  transform:translateX(-50%);
  border:7px solid transparent;
  border-top-color:#fff8ec;
  z-index:1;
}

/* にゅるち: beside the head, clear of the face and of ぴよち below */
.char-block.nyuruchi .speech-bubble{
  top:3vh;
  left:78%;
}

/* ぴよち: floats just above the chick, which has room to spare */
.char-block.piyochi .speech-bubble{
  top:-9vh;
  left:50%;
}
