/* ---------------------------------------------------------------------------
   design.css — eyes + voice visualiser (from helmet-display.html).
   State is a class on #stage:  idle | listening | speaking
   Extra classes: armed (mic waiting for wake word), busy (waiting for the
   Worker reply), error (flashes briefly when something fails).
   --------------------------------------------------------------------------- */
:root{
  --eye: #ff8a7a;                 /* coral */
  --glow: rgba(255,138,122,.55);
  --glow-soft: rgba(255,138,122,.22);
  --glow-soft-strong: rgba(255,138,122,.32);
  --eye-size: 17vmin;
  --eye-gap: 15vmin;
  --blink-cycle: 13.7s;
}

/* Stage — rotated in portrait so the face is always landscape */
#stage{
  position:absolute;left:50%;top:50%;
  width:100dvw;height:100dvh;
  transform:translate(-50%,-50%);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:7vmin;
  background:#000;
}
@media (orientation: portrait){
  #stage{width:100dvh;height:100dvw;transform:translate(-50%,-50%) rotate(90deg)}
}

/* Eyes */
.eyes{display:flex;gap:var(--eye-gap)}
.eye{
  width:var(--eye-size);height:var(--eye-size);
  transition:transform .45s cubic-bezier(.4,0,.2,1);
  transform:scaleY(1);
  will-change:transform;
}
.lid{
  width:100%;height:100%;
  background:var(--eye);
  border-radius:30%;
  box-shadow:0 0 1.6vmin var(--glow), 0 0 6vmin var(--glow-soft);
  animation:blink var(--blink-cycle) infinite;
  transform-origin:50% 50%;
  will-change:transform;
}
/* Irregular blink schedule: single, single, double, single, long gap */
@keyframes blink{
  0%,7.6%   {transform:scaleY(1)}
  8.2%      {transform:scaleY(.06)}
  9.0%      {transform:scaleY(1)}
  29.4%     {transform:scaleY(1)}
  30.0%     {transform:scaleY(.06)}
  30.9%     {transform:scaleY(1)}
  47.0%     {transform:scaleY(1)}
  47.6%     {transform:scaleY(.06)}
  48.3%     {transform:scaleY(1)}
  49.1%     {transform:scaleY(1)}
  49.7%     {transform:scaleY(.06)}
  50.5%     {transform:scaleY(1)}
  72.8%     {transform:scaleY(1)}
  73.4%     {transform:scaleY(.06)}
  74.3%     {transform:scaleY(1)}
  100%      {transform:scaleY(1)}
}

/* State: eye shape */
.speaking  .eye{transform:scaleY(.68)}
.listening .eye{transform:scaleY(1.14) scaleX(1.05)}
.listening .lid{animation:blink var(--blink-cycle) infinite, breathe 3.2s ease-in-out infinite}
@keyframes breathe{
  0%,100%{box-shadow:0 0 1.6vmin var(--glow), 0 0 6vmin var(--glow-soft)}
  50%    {box-shadow:0 0 2.4vmin var(--glow), 0 0 8vmin var(--glow-soft-strong)}
}

/* Voice visualiser — a thin line that becomes bars when speaking */
.viz{
  position:absolute;
  left:50%;bottom:calc(env(safe-area-inset-bottom, 0px) + 2.5vmin);
  transform:translateX(-50%);
  width:22vmin;height:2.2vmin;
  display:flex;align-items:center;justify-content:space-between;
  opacity:.85;
}
.viz::before{
  content:"";position:absolute;left:0;right:0;top:50%;
  height:.5px;margin-top:-.25px;
  background:var(--eye);
  opacity:.7;
  box-shadow:0 0 .4vmin var(--glow);
  transition:opacity .4s;
}
.bar{
  width:.35vmin;height:100%;
  background:var(--eye);
  border-radius:.5px;
  transform:scaleY(0);
  transform-origin:50% 50%;
  transition:transform .3s;
  will-change:transform;
}
.speaking .viz::before{opacity:0}
.speaking .bar{animation:wave var(--d,.6s) ease-in-out infinite alternate;animation-delay:var(--o,0s)}
@keyframes wave{
  from{transform:scaleY(.06)}
  to  {transform:scaleY(var(--h,.8))}
}

/* ---------------------------------------------------------------------------
   Status caption — one quiet line under the eyes that says what's going on.
   --------------------------------------------------------------------------- */
.caption{
  position:absolute;
  left:50%;bottom:calc(env(safe-area-inset-bottom, 0px) + 7.5vmin);
  transform:translateX(-50%);
  max-width:70vw;
  font-family:-apple-system,system-ui,sans-serif;
  font-size:2.6vmin;
  line-height:1.35;
  letter-spacing:.04em;
  text-align:center;
  color:var(--eye);
  opacity:.55;
  transition:opacity .35s, color .35s;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.caption.status{ text-transform:uppercase; letter-spacing:.22em; font-size:2.1vmin; }
.caption.reply { white-space:normal; opacity:.8; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; }
.caption.heard { opacity:.85; }
.caption.error { color:#ff5a5a; opacity:.9; text-transform:none; letter-spacing:.04em; }
.caption:empty { opacity:0; }

/* Mic off: the line is dim.  Armed: the line is lit and breathes gently. */
.viz::before{ opacity:.25; }
.armed .viz::before{ opacity:.7; animation:linebreathe 3.2s ease-in-out infinite; }
@keyframes linebreathe{
  0%,100%{ box-shadow:0 0 .4vmin var(--glow); }
  50%    { box-shadow:0 0 1.2vmin var(--glow); }
}

/* Thinking: eyes glance up, a faint ripple runs along the line. */
.busy .eye{ transform:translateY(-1.6vmin) scaleY(.92); }
.busy .viz::before{ opacity:0; }
.busy .bar{ animation:think 1.1s ease-in-out infinite alternate; animation-delay:calc(var(--o,0s) * 3); }
@keyframes think{
  from{ transform:scaleY(.06); opacity:.5; }
  to  { transform:scaleY(.3);  opacity:1; }
}

/* Error: a brief red tint on the eyes. */
.lid{ transition:background .3s, box-shadow .3s; }
.error .lid{ background:#ff4a4a; box-shadow:0 0 1.6vmin rgba(255,74,74,.6), 0 0 6vmin rgba(255,74,74,.25); }
