/* ═══════════════════════════════════════════════
   login-chars.css  —  Animated Characters Login
   ═══════════════════════════════════════════════ */

/* ─── Layout ─── */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%;overflow:hidden}
body{
  display:grid;grid-template-columns:1fr 1fr;
  height:100vh;max-height:100vh;
  font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif;
}

/* ════════════════════
   ENTRANCE ANIMATIONS
   ════════════════════ */
@keyframes panelLeft{
  from{opacity:0;transform:translateX(-48px)}
  to  {opacity:1;transform:translateX(0)}
}
@keyframes panelRight{
  from{opacity:0;transform:translateX(40px)}
  to  {opacity:1;transform:translateX(0)}
}
@keyframes fadeDown{
  from{opacity:0;transform:translateY(-14px)}
  to  {opacity:1;transform:translateY(0)}
}
@keyframes fadeUp{
  from{opacity:0;transform:translateY(12px)}
  to  {opacity:1;transform:translateY(0)}
}
@keyframes formFade{
  from{opacity:0;transform:translateY(12px)}
  to  {opacity:1;transform:translateY(0)}
}

/* ═══════════════════════════════════════════════════════════════════════
   CHARACTER ENTRANCE — 4 screen-edge directions with distinct personalities
   🟠 Orange  : ROLLS IN from LEFT   — rotating horizontal slide
   🟣 Purple  : BURSTS UP from BOTTOM — compressed rise, elongated momentum
   ⚫ Black   : TUMBLES DOWN from TOP  — spinning fall, heavy landing
   🟡 Yellow  : LEAPS IN from RIGHT   — airborne arc, bouncy landing
   Stagger: O 0.08s → P 0.28s → B 0.50s → Y 0.72s    overall = linear
   ═══════════════════════════════════════════════════════════════════════ */

@keyframes charDropO{          /* 🟠 ROLLS IN from LEFT — rotation tied to travel */
  0%  {
    opacity:0;
    transform:translateX(-620px) rotate(-220deg) scaleX(.88) scaleY(.86);
    animation-timing-function:cubic-bezier(.32,0,.82,.2);  /* steep ease-in roll */
  }
  46% {
    opacity:1;
    transform:translateX(24px) rotate(18deg) scaleX(.82) scaleY(1.16);
    animation-timing-function:cubic-bezier(0,.6,.38,1);    /* ease-out decel */
  }
  62% {
    transform:translateX(-14px) rotate(-5deg) scaleX(1.10) scaleY(.92);
    animation-timing-function:cubic-bezier(.42,0,.58,1);
  }
  76% {
    transform:translateX(5px) rotate(1.5deg) scaleX(.97) scaleY(1.02);
    animation-timing-function:cubic-bezier(.42,0,.58,1);
  }
  88% {transform:translateX(-2px) rotate(-.5deg);}
  100%{transform:translate(0,0) rotate(0) scaleX(1) scaleY(1);}
}

@keyframes charDropP{          /* 🟣 BURSTS UP from BOTTOM — compressed to elongated */
  0%  {
    opacity:0;
    transform:translateY(700px) scaleX(.96) scaleY(.78);   /* squished below screen */
    animation-timing-function:cubic-bezier(.28,0,.72,.2);  /* ease-in rise */
  }
  48% {
    opacity:1;
    transform:translateY(-28px) scaleX(1.06) scaleY(1.14); /* overshoots, stretched */
    animation-timing-function:cubic-bezier(0,.6,.4,1);
  }
  63% {
    transform:translateY(16px) scaleX(1.04) scaleY(.92);
    animation-timing-function:cubic-bezier(.42,0,.58,1);
  }
  77% {
    transform:translateY(-7px) scaleX(.99) scaleY(1.03);
    animation-timing-function:cubic-bezier(.42,0,.58,1);
  }
  88% {transform:translateY(3px);}
  100%{transform:translate(0,0) scaleX(1) scaleY(1);}
}

@keyframes charDropB{          /* ⚫ TUMBLES DOWN from TOP — full spin, heavy land */
  0%  {
    opacity:0;
    transform:translateY(-700px) rotate(0deg) scaleX(.88) scaleY(.88);
    animation-timing-function:cubic-bezier(.28,0,.72,.2);
  }
  30% {                        /* mid-spin during fall */
    opacity:1;
    transform:translateY(-340px) rotate(195deg) scaleX(.90) scaleY(.92);
    animation-timing-function:cubic-bezier(.36,0,.88,.3);
  }
  50% {                        /* impact — full spin complete, heavy squash */
    transform:translateY(20px) rotate(385deg) scaleX(1.14) scaleY(.84);
    animation-timing-function:cubic-bezier(0,.6,.4,1);
  }
  65% {
    transform:translateY(-22px) rotate(360deg) scaleX(.94) scaleY(1.12);
    animation-timing-function:cubic-bezier(.42,0,.58,1);
  }
  78% {
    transform:translateY(9px) rotate(360deg) scaleX(1.03) scaleY(.96);
    animation-timing-function:cubic-bezier(.42,0,.58,1);
  }
  88% {transform:translateY(-4px) rotate(360deg) scaleX(.99) scaleY(1.01);}
  100%{transform:translate(0,0) rotate(360deg) scaleX(1) scaleY(1);}
}

@keyframes charDropY{          /* 🟡 LEAPS IN from RIGHT — arc trajectory, bouncy */
  0%  {
    opacity:0;
    transform:translateX(620px) rotate(14deg) scaleX(.90) scaleY(.86);
    animation-timing-function:cubic-bezier(.32,0,.82,.2);
  }
  28% {                        /* peak of leap — airborne, stretched */
    opacity:1;
    transform:translateX(80px) translateY(-52px) rotate(-6deg) scaleX(.88) scaleY(1.16);
    animation-timing-function:cubic-bezier(.6,0,.88,.4);
  }
  50% {                        /* first landing */
    transform:translateX(-14px) translateY(0) rotate(4deg) scaleX(1.12) scaleY(.86);
    animation-timing-function:cubic-bezier(0,.6,.4,1);
  }
  64% {                        /* small bounce */
    transform:translateX(10px) translateY(-18px) rotate(-2deg) scaleX(.96) scaleY(1.08);
    animation-timing-function:cubic-bezier(.42,0,.58,1);
  }
  77% {
    transform:translateX(-3px) translateY(0) rotate(1deg) scaleX(1.03) scaleY(.96);
    animation-timing-function:cubic-bezier(.42,0,.58,1);
  }
  88% {transform:translateX(1px) translateY(-4px);}
  100%{transform:translate(0,0) rotate(0) scaleX(1) scaleY(1);}
}

/* ─── Mouth grow — each char triggers after their landing bounce ─── */
@keyframes mouthGrow{
  0%  {transform:scaleX(0);   opacity:0;}
  55% {transform:scaleX(1.26);opacity:1;}
  75% {transform:scaleX(0.90);}
  90% {transform:scaleX(1.06);}
  100%{transform:scaleX(1);   opacity:1;}
}

/* ════════════════════════
   SUCCESS / ERROR EFFECTS
   ════════════════════════ */
@keyframes successHopTall{
  0%  {transform:translateY(0)}
  28% {transform:translateY(-72px) scaleY(1.06)}
  50% {transform:translateY(18px)  scaleY(.93)}
  68% {transform:translateY(-22px)}
  84% {transform:translateY(6px)}
  100%{transform:translateY(0)}
}
@keyframes successHopMid{
  0%  {transform:translateY(0)}
  30% {transform:translateY(-52px) scaleY(1.05)}
  52% {transform:translateY(14px)  scaleY(.95)}
  70% {transform:translateY(-16px)}
  86% {transform:translateY(5px)}
  100%{transform:translateY(0)}
}
@keyframes successHopSmall{
  0%  {transform:translateY(0)}
  32% {transform:translateY(-38px) scaleY(1.04)}
  54% {transform:translateY(10px)  scaleY(.97)}
  72% {transform:translateY(-10px)}
  88% {transform:translateY(3px)}
  100%{transform:translateY(0)}
}
@keyframes errorJitterTall{
  0%  {transform:translateY(0)     scaleX(1)    scaleY(1)}
  12% {transform:translateY(-40px) scaleX(.91)  scaleY(1.09)}
  26% {transform:translateY(14px)  scaleX(1.07) scaleY(.88)}
  38% {transform:translateY(-16px) rotate(-2deg)}
  50% {transform:translateY(6px)   rotate(1.5deg)}
  62% {transform:translateY(-10px) rotate(-1.2deg)}
  74% {transform:translateY(4px)   rotate(.8deg)}
  86% {transform:translateY(-3px)}
  100%{transform:translateY(0)     scaleX(1)    scaleY(1)}
}
@keyframes errorJitterMid{
  0%  {transform:translateY(0)}
  14% {transform:translateY(-26px) scaleY(1.05)}
  28% {transform:translateY(8px)   scaleY(.94)}
  42% {transform:translateY(-12px) rotate(1.5deg)}
  56% {transform:translateY(5px)   rotate(-1deg)}
  70% {transform:translateY(-5px)}
  84% {transform:translateY(2px)}
  100%{transform:translateY(0)}
}
@keyframes errorJitterSmall{
  0%  {transform:translateY(0)}
  18% {transform:translateY(-14px) scaleX(1.04)}
  34% {transform:translateY(5px)   scaleX(.97)}
  52% {transform:translateY(-7px)  rotate(-.8deg)}
  68% {transform:translateY(3px)   rotate(.5deg)}
  84% {transform:translateY(-2px)}
  100%{transform:translateY(0)}
}
@keyframes formShake{
  0%,100%{transform:translateX(0) rotate(0)}
  12%{transform:translateX(-14px) rotate(-.5deg)}
  26%{transform:translateX(12px)  rotate(.4deg)}
  40%{transform:translateX(-9px)  rotate(-.3deg)}
  54%{transform:translateX(7px)   rotate(.2deg)}
  68%{transform:translateX(-5px)}
  82%{transform:translateX(3px)}
}
@keyframes successPulse{
  0%  {transform:scale(1);box-shadow:0 0 0 0 rgba(34,197,94,0)}
  35% {transform:scale(1.05);box-shadow:0 0 0 14px rgba(34,197,94,.22)}
  70% {transform:scale(.99);box-shadow:0 0 0 6px rgba(34,197,94,.08)}
  100%{transform:scale(1);box-shadow:0 0 0 0 rgba(34,197,94,0)}
}
@keyframes errorPulse{
  0%  {transform:scale(1);box-shadow:0 0 0 0 rgba(239,68,68,0)}
  30% {transform:scale(.982);box-shadow:0 0 0 12px rgba(239,68,68,.2)}
  65% {transform:scale(1.01);box-shadow:0 0 0 4px rgba(239,68,68,.06)}
  100%{transform:scale(1);box-shadow:0 0 0 0 rgba(239,68,68,0)}
}
@keyframes errorBtnShake{
  0%  {transform:translateX(0)}
  12% {transform:translateX(-10px) rotate(-.6deg)}
  26% {transform:translateX(9px)   rotate(.5deg)}
  40% {transform:translateX(-7px)  rotate(-.4deg)}
  55% {transform:translateX(5px)}
  70% {transform:translateX(-3px)}
  84% {transform:translateX(1px)}
  100%{transform:translateX(0)}
}
@keyframes errorFlash{
  0%  {opacity:0}
  18% {opacity:1}
  60% {opacity:.6}
  100%{opacity:0}
}

/* ════════════════
   LEFT PANEL
   ════════════════ */
.lp{
  position:relative;overflow:hidden;
  background:linear-gradient(135deg,#c8c8c8 0%,#b8b8b8 50%,#acacac 100%);
  display:flex;flex-direction:column;justify-content:space-between;
  padding:48px;
  animation:panelLeft .55s cubic-bezier(.25,.46,.45,.94) both;
  /* GPU layer */
  transform:translateZ(0);
  will-change:transform;
}
.lp::before{
  content:'';position:absolute;inset:0;
  background-image:
    linear-gradient(rgba(255,255,255,.07) 1px,transparent 1px),
    linear-gradient(90deg,rgba(255,255,255,.07) 1px,transparent 1px);
  background-size:20px 20px;pointer-events:none;
}
.brand{
  display:flex;align-items:center;text-decoration:none;
  position:relative;z-index:1;
  animation:fadeDown .4s .15s ease both;
}
.brand-logo{
  height:42px;width:auto;max-width:180px;
  object-fit:contain;display:block;
  filter:drop-shadow(0 1px 3px rgba(0,0,0,.18));
}

/* ─── stage ─── */
.stage{
  position:absolute;
  bottom:56px;left:50%;
  width:550px;height:440px;   /* original: 550×400 + 40 typing headroom */
  /* scale(1.3): visual width 715px fills the 720px panel naturally
     transform-origin:center bottom keeps characters anchored to the same baseline
     all child pixel values (positions, eye sizes, mouth) auto-scale — no JS changes needed */
  transform: translateX(-50%) scale(1.3);
  transform-origin: center bottom;
}

/* wrapper  — entrance drop animation only; JS body skew lives in .ch */
.cw{
  position:absolute;bottom:0;
  transform-origin:bottom center;
}
/* character positions — staggered drop entrance
   Overall timing MUST be linear so per-keyframe animation-timing-function takes effect;
   duration 1.05s gives fall+squash+3 bounces at comfortable natural speed             */
/* durations tuned per-character: roll needs 1.2s; tumble spin 1.25s; leap 1.15s */
.cw-o{left:0;    z-index:3;animation:charDropO 1.20s linear .08s both;}
.cw-p{left:70px; z-index:1;animation:charDropP 1.05s linear .28s both;}
.cw-b{left:240px;z-index:2;animation:charDropB 1.25s linear .50s both;}
.cw-y{left:310px;z-index:4;animation:charDropY 1.15s linear .72s both;}

/* inner char — JS exclusively sets transform; NO CSS transition (avoids rAF/CSS conflict)
   will-change:transform creates GPU compositing layer automatically        */
.ch{
  transform-origin:bottom center;
  position:relative;
  will-change:transform;
}

/* eyes — JS sets left/top via JS lerp; NO CSS position transition (avoids rAF conflict) */
.eyes{position:absolute;display:flex;pointer-events:none;}

/* eyeball — only blink (height→2px) needs CSS transition, nothing else */
.eb{
  border-radius:50%;background:#fff;
  position:relative;flex-shrink:0;
  overflow:hidden;
  display:flex;align-items:center;justify-content:center;
  transition:height 150ms ease;
}
.eb.blink{height:2px!important;}

/* pupil — transition 0.1s ease-out matches original source exactly */
.pu{
  border-radius:50%;background:#2d2d2d;
  flex-shrink:0;
  transition:transform .1s ease-out;
}
/* orange/yellow dots — no transition (direct rAF) */
.dt{border-radius:50%;background:#2d2d2d;position:absolute;}

/* ─── Base mouth — CSS defines shape, JS sets position (left/top) only ─── */
.mth{position:absolute;transform-origin:left center;}

/* 🟠 Orange — wider pill, slightly thicker → more expressive / dominant */
#mthO{
  width:70px;height:6px;
  background:#2d2d2d;border-radius:99px;
  animation:mouthGrow .44s cubic-bezier(.34,1.56,.64,1) .78s both;
}

/* 🟣 Purple — medium white pill → calm / composed */
#mthP{
  width:66px;height:5px;
  background:#fff;border-radius:99px;
  animation:mouthGrow .42s cubic-bezier(.34,1.56,.64,1) .94s both;
}

/* ⚫ Black — narrow white pill → reserved / stern */
#mthB{
  width:50px;height:5px;
  background:#fff;border-radius:99px;
  animation:mouthGrow .40s cubic-bezier(.34,1.56,.64,1) 1.28s both;
}

/* 🟡 Yellow — original wide dark pill (source-accurate) */
#mthY{
  width:80px;height:4px;
  background:#2d2d2d;border-radius:99px;
  animation:mouthGrow .42s cubic-bezier(.34,1.56,.64,1) 1.45s both;
}

/* char shapes — exact from source; #chP height transition for typing grow effect */
#chP{width:180px;height:400px;background:#6c3ff5;border-radius:10px 10px 0 0;transition:height .7s cubic-bezier(.4,0,.2,1);}
#chB{width:120px;height:310px;background:#2d2d2d;border-radius:8px  8px  0 0;}
#chO{width:240px;height:200px;background:#ff9b6b;border-radius:120px 120px 0 0;}
#chY{width:140px;height:230px;background:#e8d754;border-radius:70px  70px  0 0;}

/* blobs */
.blob{position:absolute;border-radius:50%;filter:blur(55px);pointer-events:none;opacity:.18;}
.bl1{width:260px;height:260px;background:#6c3ff5;top:-80px;right:-60px;}
.bl2{width:180px;height:180px;background:#f97316;bottom:60px;left:-50px;}

/* footer */
.lp-foot{display:flex;gap:24px;position:relative;z-index:1;animation:fadeUp .4s .9s ease both;}
.lp-foot a{font-size:13px;color:rgba(0,0,0,.4);text-decoration:none;transition:color .2s;}
.lp-foot a:hover{color:#111;}

/* ════════════════════
   SUCCESS / ERROR CSS
   ════════════════════ */
.btn-ihb.is-success{background:#22c55e;color:#fff;animation:successPulse .8s ease;}
.btn-ihb.is-error{background:#ef4444;color:#fff;animation:errorPulse .55s ease,errorBtnShake .55s ease;}
.fb.is-error{animation:formShake .55s ease;}
.stage.is-error .cw-p{animation:errorJitterTall  .75s cubic-bezier(.36,.07,.19,.97);}
.stage.is-error .cw-b{animation:errorJitterMid   .75s cubic-bezier(.36,.07,.19,.97) .04s;}
.stage.is-error .cw-o{animation:errorJitterSmall  .75s cubic-bezier(.36,.07,.19,.97) .08s;}
.stage.is-error .cw-y{animation:errorJitterMid   .75s cubic-bezier(.36,.07,.19,.97) .02s;}
.stage.is-success .cw-p{animation:successHopTall 1.0s cubic-bezier(.34,1.3,.64,1);}
.stage.is-success .cw-b{animation:successHopMid  1.0s cubic-bezier(.34,1.3,.64,1) .06s;}
.stage.is-success .cw-o{animation:successHopSmall 1.0s cubic-bezier(.34,1.3,.64,1) .12s;}
.stage.is-success .cw-y{animation:successHopMid  1.0s cubic-bezier(.34,1.3,.64,1) .03s;}

/* error flash overlay (JS-injected) */
.error-flash{
  position:fixed;inset:0;pointer-events:none;z-index:9999;
  background:rgba(239,68,68,.13);
  animation:errorFlash .55s ease forwards;
}

/* ═══════════════
   RIGHT PANEL
   ═══════════════ */
.rp{
  background:#09090b;
  display:flex;flex-direction:column;
  align-items:center;justify-content:flex-start;
  padding:0 64px;overflow-y:auto;
  animation:panelRight .55s .05s cubic-bezier(.25,.46,.45,.94) both;
  transform:translateZ(0);
  will-change:transform;
}
.fb{
  width:100%;max-width:360px;
  margin:auto;        /* 内容短时垂直居中，超出时正常滚动 */
  padding:48px 0;     /* 顶部/底部留白替代原 rp 的 padding */
}
.fh{text-align:center;margin-bottom:32px;animation:formFade .4s .5s ease both;}
.fh-logo{
  width:52px;height:52px;object-fit:contain;border-radius:12px;
  margin:-20px auto 14px;display:block;
  box-shadow:0 2px 12px rgba(0,0,0,.35);
}
.fh h1{font-size:28px;font-weight:700;color:#fff;margin-bottom:6px;letter-spacing:-.5px;}
.fh p{font-size:14px;color:#71717a;}

.fi{margin-bottom:16px;}
.fi:nth-of-type(1){animation:formFade .4s .60s ease both;}
.fi:nth-of-type(2){animation:formFade .4s .67s ease both;}
.fi label{display:block;font-size:14px;font-weight:600;color:#f4f4f5;margin-bottom:7px;}
.fi input{
  width:100%;height:48px;background:#09090b;
  border:1px solid rgba(255,255,255,.15);border-radius:8px;
  padding:0 42px 0 14px;font-size:14px;color:#fff;outline:none;
  transition:border-color .2s,box-shadow .2s;
}
.fi input:focus{border-color:#6c3ff5;box-shadow:0 0 0 2px rgba(108,63,245,.22);}
.fi input::placeholder{color:#3f3f46;}

.pw-w{position:relative;}
.pw-t{
  position:absolute;right:13px;top:50%;transform:translateY(-50%);
  background:none;border:none;cursor:pointer;color:#52525b;padding:4px;
}
.pw-t:hover{color:#a1a1aa;}
.pw-t svg{width:16px;height:16px;display:block;}

.fopts{
  display:flex;align-items:center;justify-content:space-between;
  margin-bottom:20px;font-size:13px;
  animation:formFade .4s .74s ease both;
}
.rem{display:flex;align-items:center;gap:8px;color:#a1a1aa;cursor:pointer;user-select:none;}
.rem input[type=checkbox]{width:15px;height:15px;accent-color:#6c3ff5;}
.fgt{color:#6c3ff5;text-decoration:none;font-weight:500;font-size:13px;}
.fgt:hover{color:#a78bfa;}

/* interactive hover button */
.btn-ihb{
  position:relative;width:100%;height:48px;border-radius:999px;
  background:#fff;color:#09090b;border:none;cursor:pointer;overflow:hidden;
  font-size:15px;font-weight:600;letter-spacing:.2px;
  margin-bottom:12px;
  animation:formFade .4s .81s ease both;
}
.btn-ihb-inner{
  display:flex;align-items:center;justify-content:center;
  position:absolute;inset:0;transition:transform .25s ease,opacity .25s ease;
}
.btn-ihb-front{gap:8px;}
.btn-ihb-back{transform:translateX(-30px);opacity:0;gap:8px;}
.btn-ihb:hover .btn-ihb-front{transform:translateX(30px);opacity:0;}
.btn-ihb:hover .btn-ihb-back{transform:translateX(0);opacity:1;}
.btn-ihb:active{opacity:.9;}
.btn-ihb[disabled]{cursor:wait;}
.btn-ihb.is-loading{opacity:.92;pointer-events:none;}
.btn-ihb.is-loading .btn-ihb-front{transform:translateX(0);opacity:1;}
.btn-ihb.is-loading .btn-ihb-back{transform:translateX(-30px);opacity:0;}

/* secondary button */
.btn-sec{
  width:100%;height:48px;border-radius:999px;
  background:transparent;color:#fff;
  border:1px solid rgba(255,255,255,.14);
  cursor:pointer;font-size:14px;font-weight:500;
  display:flex;align-items:center;justify-content:center;gap:8px;
  text-decoration:none;margin-bottom:24px;
  transition:background .2s;
  animation:formFade .4s .88s ease both;
}
.btn-sec:hover{background:rgba(255,255,255,.06);}
.btn-sec svg{width:18px;height:18px;flex-shrink:0;}

.srow{
  text-align:center;font-size:13px;color:#71717a;
  animation:formFade .4s .95s ease both;
}
.srow a{color:#fff;font-weight:600;text-decoration:none;}
.srow a:hover{text-decoration:underline;}

@media(max-width:820px){
  body{grid-template-columns:1fr;}
  .lp{display:none;}
  .rp{padding:40px 28px;}
}
