/* ==========================================================================
   MACROS.™ — OTP orbit
   The six digits leave the row, take up a ring around a hub, wind up, spin,
   then collapse into the middle while the code is checked. Green when it is
   right, red when it isn't. Used on sign-in and again at payment.
   ========================================================================== */
:root{ --ok:#2CE6A8; --bad:#FF4D6A; }
html[data-theme="light"]{ --ok:#00875A; --bad:#C6103A; }

.otpx{position:relative}
.otpx.orbiting input{caret-color:transparent;pointer-events:none}
.otpx.orbiting .link{opacity:0;transition:opacity .3s}

/* the track the digits run on — dotted on purpose: a solid ring at this size
   reads as a loading spinner, and this is not a wait, it is a check */
.orbit-ring{
  position:absolute;left:50%;top:50%;translate:-50% -50%;
  width:172px;height:172px;pointer-events:none;opacity:0;z-index:1;
  transition:opacity .35s var(--ease);
}
.orbit-ring.on{opacity:1}
.orbit-ring circle{
  fill:none;stroke:var(--stroke-2);stroke-width:1.5;
  stroke-dasharray:2 8;stroke-linecap:round;
  vector-effect:non-scaling-stroke;
  transform-origin:50% 50%;animation:ringspin 9s linear infinite;
}
@keyframes ringspin{to{transform:rotate(360deg)}}

.orbit-hub{
  position:absolute;left:50%;top:50%;translate:-50% -50%;
  width:8px;height:8px;border-radius:50%;background:var(--ash-2);
  opacity:0;transition:opacity .3s var(--ease);z-index:1;
}
.orbit-hub.on{opacity:1}

.otpx input{position:relative;z-index:2;will-change:transform}
.otpx.orbiting input{border-color:var(--stroke-2)}
.otpx input.verdict-ok{border-color:var(--ok);color:var(--ok);
  box-shadow:0 0 0 1px var(--ok),0 0 26px -6px var(--ok)}
.otpx input.verdict-bad{border-color:var(--bad);color:var(--bad);
  box-shadow:0 0 0 1px var(--bad),0 0 26px -6px var(--bad)}

/* the result that lands in the middle once the digits have collapsed */
.orbit-seal{
  position:absolute;left:50%;top:50%;translate:-50% -50%;
  width:66px;height:66px;border-radius:50%;display:grid;place-items:center;
  opacity:0;scale:.5;z-index:3;pointer-events:none;
  transition:opacity .3s var(--ease),scale .5s cubic-bezier(.34,1.5,.5,1);
}
.orbit-seal.on{opacity:1;scale:1}
.orbit-seal svg{width:34px;height:34px;fill:none;stroke-width:3.4;
  stroke-linecap:round;stroke-linejoin:round}
.orbit-seal.ok{background:color-mix(in srgb,var(--ok) 16%,transparent);
  box-shadow:0 0 34px -6px var(--ok)}
.orbit-seal.ok svg{stroke:var(--ok)}
.orbit-seal.bad{background:color-mix(in srgb,var(--bad) 16%,transparent);
  box-shadow:0 0 34px -6px var(--bad)}
.orbit-seal.bad svg{stroke:var(--bad)}
.orbit-seal path{stroke-dasharray:48;stroke-dashoffset:48}
.orbit-seal.on path{animation:drawseal .5s .1s var(--ease) forwards}
@keyframes drawseal{to{stroke-dashoffset:0}}

/* --------------------------------------------------------------------------
   The message card. In the demo build the code is known, so rather than make
   somebody copy it out of a hint line, it arrives the way a real SMS does and
   fills itself when asked.
   -------------------------------------------------------------------------- */
.smsx{
  position:absolute;left:0;right:0;bottom:-6px;z-index:6;
  display:flex;align-items:center;gap:12px;
  padding:12px 12px 12px 14px;border-radius:16px;
  background:var(--glass-2);border:1px solid var(--stroke-2);
  backdrop-filter:blur(20px) saturate(170%);
  -webkit-backdrop-filter:blur(20px) saturate(170%);
  box-shadow:inset 0 1px 0 var(--rim-hi),0 18px 40px -18px rgba(0,0,0,.7);
  transform:translateY(150%);opacity:0;
  transition:transform .62s cubic-bezier(.24,1.3,.4,1),opacity .4s var(--ease);
}
.smsx.on{transform:none;opacity:1}
.smsx .ic{width:34px;height:34px;border-radius:10px;flex:none;display:grid;place-items:center;
  background:var(--glass-2);border:1px solid var(--stroke)}
.smsx .ic svg{width:17px;height:17px;stroke:var(--ash);fill:none;stroke-width:1.8}
.smsx .tx{min-width:0;flex:1}
.smsx .tx b{display:block;font-family:var(--mono);font-size:.6rem;letter-spacing:.2em;
  text-transform:uppercase;color:var(--ash-2);margin-bottom:2px}
.smsx .tx span{font-size:.88rem;color:var(--chalk);display:block;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.smsx .tx span em{font-style:normal;font-family:var(--mono);font-weight:700;color:var(--volt)}
.smsx button{
  flex:none;padding:9px 18px;border-radius:999px;border:0;cursor:pointer;
  font-size:.83rem;font-weight:600;background:var(--chalk);color:var(--ink);
  min-height:40px;transition:transform .25s var(--ease)}
.smsx button:hover{transform:translateY(-1px)}
.smsx button:active{transform:scale(.96)}

@media (max-width:520px){
  .orbit-ring{width:136px;height:136px}
  .smsx{padding:10px;gap:9px}
  .smsx .tx span{font-size:.8rem}
  .smsx button{padding:9px 14px}
}

/* --------------------------------------------------------- payment orbit -- */
/* The same idea at checkout: the amount breaks into its digits, they orbit
   while the payment is authorised, and collapse into the tick. */
.payx{position:relative;display:grid;place-items:center;min-height:190px}
.payx .amt{display:flex;gap:2px;font-family:var(--mono);font-weight:700;
  font-size:clamp(1.8rem,6vw,2.6rem);color:var(--chalk);z-index:2}
.payx .amt span{display:inline-block;will-change:transform}
.payx .lbl{position:absolute;bottom:6px;left:0;right:0;text-align:center;
  font-family:var(--mono);font-size:.66rem;letter-spacing:.2em;
  text-transform:uppercase;color:var(--ash-2)}

@media (prefers-reduced-motion:reduce){
  .orbit-ring circle{animation:none}
  .smsx{transition:opacity .3s}
}
