/* ============================================================
   Rewarding a form.

   Every state a field can be in, and every animation that marks finishing
   something. Loaded on the sign-in, registration and profile pages, on top of
   either login.css or app.css -- so everything here is written against BOTH
   markups: `.field > .control > input.input` (the public pages) and
   `.fld > input` (the dashboard).

   Three rules run through all of it:

   1. Never colour alone. Every state also carries an icon and words, because
      roughly one man in twelve cannot tell the amber from the green.
   2. Motion is a bonus, never the message. Under prefers-reduced-motion every
      animation below collapses to a fade, and the page still says everything
      it was going to say.
   3. Nothing shouts. A form that pulses and pings at every keystroke is worse
      than a silent one; the feedback grows with the size of what was finished.
   ============================================================ */

:root {
  --rw-ok: #16a34a;
  --rw-ok-bg: rgba(22, 163, 74, .08);
  --rw-need: #f59e0b;
  --rw-need-bg: rgba(245, 158, 11, .07);
  --rw-bad: var(--danger, #dc2626);
  --rw-spring: cubic-bezier(.34, 1.56, .64, 1);
}

/* ---------------------------------------------------------- the field ---- */
/* The element that directly wraps the input; JS marks it so the tick has
   something to be positioned against without assuming either page's markup. */
.rw-holder { position: relative; }

.rw-holder > input,
.rw-holder > select,
.rw-holder > textarea {
  transition: border-color .18s ease, box-shadow .18s ease, background-color .18s ease;
}

/* Required, still empty. Amber is an invitation, not a telling-off, so it is
   a tint and a border rather than an error message. */
.rw-need > input:not(:focus),
.rw-need > select:not(:focus),
.rw-need > textarea:not(:focus) {
  border-color: var(--rw-need) !important;
  background-color: var(--rw-need-bg);
}

/* Wrong. */
.rw-bad > input,
.rw-bad > select,
.rw-bad > textarea {
  border-color: var(--rw-bad) !important;
  background-color: rgba(220, 38, 38, .05);
}

/* Right. */
.rw-ok > input,
.rw-ok > select,
.rw-ok > textarea {
  border-color: var(--rw-ok) !important;
  background-color: var(--rw-ok-bg);
  padding-right: 40px;
}

/* A soft glow on focus, in whichever colour the field is currently in. */
.rw-holder > input:focus,
.rw-holder > select:focus,
.rw-holder > textarea:focus {
  box-shadow: 0 0 0 4px rgba(39, 133, 117, .16);
}
.rw-ok > input:focus, .rw-ok > select:focus, .rw-ok > textarea:focus {
  box-shadow: 0 0 0 4px rgba(22, 163, 74, .18);
}
.rw-bad > input:focus, .rw-bad > select:focus, .rw-bad > textarea:focus {
  box-shadow: 0 0 0 4px rgba(220, 38, 38, .16);
}
.rw-need > input:focus, .rw-need > select:focus, .rw-need > textarea:focus {
  box-shadow: 0 0 0 4px rgba(245, 158, 11, .18);
}

/* Some fields draw their border on a WRAPPER, not on the input: the phone
   boxes put a fixed "+44" beside a borderless input inside .telgroup /
   .telbox. Colouring the input there paints a line nobody can see. */
.telgroup.rw-ok, .telbox.rw-ok,
.control.rw-ok:has(> .telgroup) { border-color: var(--rw-ok) !important; background: var(--rw-ok-bg); }
.telgroup.rw-bad, .telbox.rw-bad { border-color: var(--rw-bad) !important; background: rgba(220, 38, 38, .05); }
.telgroup.rw-need, .telbox.rw-need { border-color: var(--rw-need) !important; background: var(--rw-need-bg); }
.telgroup.rw-ok > input, .telbox.rw-ok > input,
.telgroup.rw-bad > input, .telbox.rw-bad > input,
.telgroup.rw-need > input, .telbox.rw-need > input { background: transparent; }

/* ----------------------------------------------------------- the tick ---- */
.rw-tick {
  position: absolute; right: 11px; top: 50%;
  width: 20px; height: 20px; margin-top: -10px;
  display: grid; place-items: center;
  border-radius: 50%; background: var(--rw-ok); color: #fff;
  pointer-events: none;
  /* VISIBLE AT REST, and the animation is only the way it arrives.

     This started as `opacity: 0; transform: scale(0)` with the animation
     filling forwards, which works right up until the tick is created inside a
     step that is still hidden -- a CSS animation does not run on a
     display:none element, so it never left the start frame and the tick was
     invisible for every answer already on file when the page loaded. An
     animation must never be the only thing that makes something visible. */
  opacity: 1; transform: scale(1);
}
.rw-tick svg { width: 12px; height: 12px; display: block; }
/* The entrance is a CLASS the script adds, and only when the field is
   actually on screen. Assigning the animation to every tick meant one created
   inside a hidden step sat on its first frame -- opacity 0, scale 0 -- and
   simply never appeared, because an animation on a display:none element does
   not run and nothing else was making the tick visible. */
.rw-tick.rw-pop-in { animation: rw-pop .2s var(--rw-spring); }

@keyframes rw-pop {
  from { opacity: 0; transform: scale(0); }
  60%  { opacity: 1; transform: scale(1.18); }
  to   { opacity: 1; transform: scale(1); }
}

/* A textarea's tick belongs at the top: the middle of six rows is nowhere. */
.rw-holder > textarea ~ .rw-tick { top: 16px; margin-top: 0; }

/* --------------------------------------------------------- the message --- */
.rw-msg {
  display: flex; gap: 6px; align-items: flex-start;
  margin: 6px 0 0; font-size: 12.4px; line-height: 1.45;
  color: var(--rw-bad);
}
.rw-msg[hidden] { display: none !important; }   /* .rw-msg sets display */
.rw-msg svg { width: 13px; height: 13px; flex: none; margin-top: 2px; }
.rw-msg.is-need { color: var(--rw-need); }

/* A group of buttons shows its state on the group, since no single button
   is the answer. Subtle: these already show which one is chosen. */
.segbtns.rw-need, .seg.rw-need, [role="radiogroup"].rw-need {
  border-radius: 12px;
  box-shadow: 0 0 0 1.5px var(--rw-need);
}
.segbtns.rw-bad, .seg.rw-bad, [role="radiogroup"].rw-bad {
  border-radius: 12px;
  box-shadow: 0 0 0 1.5px var(--rw-bad);
}
.segbtns.rw-ok, .seg.rw-ok, [role="radiogroup"].rw-ok { box-shadow: none; }
/* Never a tick inside a button. */
.segbtn > .rw-tick, .pick-card > .rw-tick, label.segbtn .rw-tick { display: none !important; }

/* ---------------------------------------------------------- the shake ---- */
.rw-shake { animation: rw-shake .34s ease; }
@keyframes rw-shake {
  10%, 90% { transform: translateX(-1.5px); }
  20%, 80% { transform: translateX(3px); }
  30%, 50%, 70% { transform: translateX(-5px); }
  40%, 60% { transform: translateX(5px); }
}

/* ------------------------------------------------------ press feedback --- */
/* Selects, checkboxes, radios and segmented buttons get a small squash on
   change -- the physical acknowledgement a native control gives for free and
   a styled one does not. */
.rw-bounce { animation: rw-bounce .22s var(--rw-spring); }
@keyframes rw-bounce {
  0%   { transform: scale(1); }
  45%  { transform: scale(.94); }
  100% { transform: scale(1); }
}

/* ------------------------------------------------- password strength ----- */
.rw-pw { margin: 8px 0 0; }
.rw-pw-bar {
  height: 5px; border-radius: 99px; overflow: hidden;
  background: var(--line, #e5e7eb);
}
.rw-pw-bar > span {
  display: block; height: 100%; width: 0;
  border-radius: 99px; background: var(--rw-bad);
  transition: width .3s ease, background-color .3s ease;
}
.rw-pw[data-level="2"] .rw-pw-bar > span { background: var(--rw-need); }
.rw-pw[data-level="3"] .rw-pw-bar > span { background: #84cc16; }
.rw-pw[data-level="4"] .rw-pw-bar > span { background: var(--rw-ok); }
.rw-pw-word {
  display: flex; justify-content: space-between; gap: 10px;
  margin: 5px 0 0; font-size: 12px; color: var(--muted, #6b7280);
}
.rw-pw-word strong { font-weight: 650; color: inherit; }

/* Show / hide, sitting where the tick would be. */
.rw-eye {
  position: absolute; right: 8px; top: 50%; margin-top: -14px;
  width: 28px; height: 28px; display: grid; place-items: center;
  background: none; border: 0; border-radius: 7px; cursor: pointer;
  color: var(--muted, #6b7280); padding: 0;
}
.rw-eye:hover { color: var(--ink, #111827); background: rgba(0, 0, 0, .05); }
.rw-eye svg { width: 16px; height: 16px; }
/* When both could show, the tick steps aside for the button. */
.rw-holder.rw-has-eye > .rw-tick { right: 40px; }
.rw-holder.rw-has-eye > input { padding-right: 44px; }
.rw-ok.rw-has-eye > input { padding-right: 72px; }

/* ------------------------------------------------------ the sound flag --- */
.rw-sound {
  background: none; border: 0; cursor: pointer; padding: 0;
  width: 34px; height: 34px; border-radius: 9px;
  display: grid; place-items: center;
  color: var(--muted, #6b7280);
  border: 1px solid transparent;
}
.rw-sound:hover { color: var(--ink, #111827); background: rgba(0, 0, 0, .05); }
.rw-sound svg { width: 17px; height: 17px; }
.rw-sound .rw-off { display: none; }
.rw-sound[aria-pressed="false"] .rw-on { display: none; }
.rw-sound[aria-pressed="false"] .rw-off { display: block; }
/* In the brand panel on the public pages: over the dark green, out of the
   form's way entirely. */
.auth-brand { position: relative; }
.rw-sound.rw-in-brand {
  position: absolute; top: 14px; right: 14px;
  color: rgba(255, 255, 255, .82);
  border-color: rgba(255, 255, 255, .28);
}
.rw-sound.rw-in-brand:hover { color: #fff; background: rgba(255, 255, 255, .14); }

/* Only when there is nowhere else. */
.rw-sound.rw-floating {
  position: fixed; top: 12px; right: 12px; z-index: 40;
  background: var(--surface, #fff); border-color: var(--line, #e5e7eb);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .08);
}

/* ------------------------------------------------- section completion ---- */
.rw-section-done { animation: rw-glow .7s ease; }
@keyframes rw-glow {
  0%   { box-shadow: 0 0 0 0 rgba(22, 163, 74, .34); transform: translateY(0); }
  35%  { box-shadow: 0 0 0 7px rgba(22, 163, 74, 0); transform: translateY(-3px); }
  100% { box-shadow: 0 0 0 0 rgba(22, 163, 74, 0); transform: translateY(0); }
}
.rw-head-tick {
  display: inline-grid; place-items: center; vertical-align: middle;
  width: 19px; height: 19px; margin-left: 7px;
  border-radius: 50%; background: var(--rw-ok); color: #fff;
  animation: rw-pop .24s var(--rw-spring);
}
.rw-head-tick svg { width: 11px; height: 11px; }

/* The amber dot a step wears until it is finished. */
.rw-dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: var(--rw-need); flex: none;
}
.rw-slide-in { animation: rw-slide .3s var(--rw-spring); }
@keyframes rw-slide {
  from { opacity: 0; transform: translateX(-7px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* ------------------------------------------------------- the pulse ------- */
/* What a blocked Continue points at. */
.rw-pulse { animation: rw-pulse 1.1s ease 2; border-radius: 12px; }
@keyframes rw-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(245, 158, 11, .45); }
  70%  { box-shadow: 0 0 0 12px rgba(245, 158, 11, 0); }
  100% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0); }
}

/* --------------------------------------------------- the blocked note ---- */
.rw-blocked {
  display: flex; gap: 9px; align-items: flex-start;
  margin: 0 0 16px; padding: 11px 14px; border-radius: 11px;
  font-size: 13.3px; line-height: 1.5;
  color: #92400e; background: var(--rw-need-bg);
  border: 1px solid rgba(245, 158, 11, .45);
}
.rw-blocked[hidden] { display: none !important; }
.rw-blocked svg { width: 16px; height: 16px; flex: none; margin-top: 1px; }
.rw-blocked b { font-weight: 680; }

/* ------------------------------------------------- the button's tick ----- */
/* Level 3: the circle draws itself, then the tick strokes in. ~600ms total. */
.rw-btn-done { position: relative; }
.rw-btn-mark { width: 18px; height: 18px; display: block; }
.rw-btn-mark circle, .rw-btn-mark path {
  fill: none; stroke: currentColor; stroke-width: 2.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.rw-btn-mark circle {
  stroke-dasharray: 63; stroke-dashoffset: 63;
  animation: rw-draw .34s ease forwards;
}
.rw-btn-mark path {
  stroke-dasharray: 20; stroke-dashoffset: 20;
  animation: rw-draw .26s ease .32s forwards;
}
@keyframes rw-draw { to { stroke-dashoffset: 0; } }

/* --------------------------------------------------- the micro-message --- */
.rw-cheer {
  position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%);
  z-index: 90; pointer-events: none;
  display: flex; align-items: center; gap: 8px;
  padding: 10px 17px; border-radius: 99px;
  font-size: 13.6px; font-weight: 640; color: #fff;
  background: #0f766e; box-shadow: 0 8px 26px rgba(0, 0, 0, .22);
  animation: rw-cheer 2.2s ease forwards;
}
.rw-cheer svg { width: 15px; height: 15px; }
@keyframes rw-cheer {
  0%   { opacity: 0; transform: translate(-50%, 14px) scale(.94); }
  12%  { opacity: 1; transform: translate(-50%, 0) scale(1); }
  80%  { opacity: 1; transform: translate(-50%, 0) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -8px) scale(.98); }
}

/* ------------------------------------------------------ the finish ------- */
.rw-final {
  position: fixed; inset: 0; z-index: 120;
  display: grid; place-items: center; padding: 24px;
  background: rgba(8, 24, 21, .62);
  backdrop-filter: blur(3px);
  animation: rw-fade .3s ease;
}
.rw-final[hidden] { display: none !important; }
@keyframes rw-fade { from { opacity: 0; } to { opacity: 1; } }

.rw-final-card {
  position: relative; z-index: 2;
  width: min(460px, 100%); text-align: center;
  padding: 34px 28px 28px; border-radius: 20px;
  background: var(--surface, #fff); color: var(--ink, #111827);
  box-shadow: 0 24px 70px rgba(0, 0, 0, .34);
  animation: rw-rise .44s var(--rw-spring);
}
@keyframes rw-rise {
  from { opacity: 0; transform: translateY(22px) scale(.94); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.rw-final h2 { margin: 18px 0 6px; font-size: 1.32rem; font-weight: 720; letter-spacing: -.02em; }
.rw-final p  { margin: 0 auto; max-width: 34ch; font-size: 14px; line-height: 1.55;
               color: var(--muted, #6b7280); }
.rw-final-acts { display: flex; gap: 9px; justify-content: center; flex-wrap: wrap; margin-top: 22px; }

/* The big tick: the ring springs in, then the stroke draws. */
.rw-final-mark { width: 84px; height: 84px; margin: 0 auto; display: block; }
.rw-final-mark circle.ring {
  fill: rgba(22, 163, 74, .1); stroke: var(--rw-ok); stroke-width: 4;
  transform-origin: center;
  animation: rw-ring .5s var(--rw-spring);
}
.rw-final-mark path {
  fill: none; stroke: var(--rw-ok); stroke-width: 6;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 40; stroke-dashoffset: 40;
  animation: rw-draw .42s ease .3s forwards;
}
@keyframes rw-ring {
  0%   { transform: scale(0); opacity: 0; }
  70%  { transform: scale(1.1); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

.rw-final canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; z-index: 1;
}

/* ------------------------------------------------------ reduced motion --- */
/* Everything above becomes a fade. The ticks, the words, the colours and the
   sounds all still happen -- only the movement stops. */
@media (prefers-reduced-motion: reduce) {
  .rw-ok > .rw-tick,
  .rw-head-tick,
  .rw-final-card,
  .rw-cheer { animation: rw-fade .2s ease forwards; opacity: 1; transform: none; }
  .rw-tick { opacity: 1; transform: none; animation: none; }
  .rw-shake, .rw-bounce, .rw-section-done, .rw-pulse, .rw-slide-in { animation: none; }
  .rw-btn-mark circle, .rw-btn-mark path,
  .rw-final-mark circle.ring, .rw-final-mark path {
    animation: none; stroke-dashoffset: 0; transform: none; opacity: 1;
  }
  .rw-final { animation: none; }
  .rw-pw-bar > span { transition: none; }
}

/* ------------------------------------------------------------ mobile ----- */
@media (max-width: 560px) {
  .rw-cheer { bottom: 16px; font-size: 13px; padding: 9px 15px; }
  .rw-final-card { padding: 28px 20px 22px; }
  .rw-final-mark { width: 68px; height: 68px; }
  .rw-final-acts .btn, .rw-final-acts .btn-primary { width: 100%; }
}
