/**
 * Recovering an account.
 *
 * Two different jobs, and they follow different rules.
 *
 * The **address field** belongs to a React bundle, so everything it shows is
 * drawn here from data attributes — a message, a state, a tick — because CSS is
 * not something React manages and cannot be undone by a re-render. Injecting
 * elements into that tree is what hung the whole application once.
 *
 * The **panel** is appended to the body and is ours, so it holds real elements
 * and is styled like anything else.
 */

@property --rp-at {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

.auth-overlay,
.rp-wrap {
  --rp-bad: #c0392b;
  --rp-warn: #a8620a;
  --rp-good: #12805c;
  --rp-note: #4b5a72;
  --rp-ink: #16233a;
  --rp-sheet: #ffffff;
  --rp-line: rgba(15, 30, 60, .14);
  --rp-track: rgba(15, 30, 60, .12);
  --rp-veil: rgba(10, 18, 34, .55);
}
html[data-theme="dark"] {
  .auth-overlay,
  .rp-wrap {
    --rp-bad: #ff9a8f;
    --rp-warn: #f5bf5a;
    --rp-good: #6fdcae;
    --rp-note: #a9b8cf;
    --rp-ink: #e8eefb;
    --rp-sheet: #161d2b;
    --rp-line: rgba(150, 180, 230, .2);
    --rp-track: rgba(150, 180, 230, .18);
    --rp-veil: rgba(4, 8, 16, .68);
  }
}

/* ── The address field ─────────────────────────────────────────────────────
   Only on the recovery form: it is the one view with an address and no
   password, which is a steadier tell than any heading. */
.auth-form-wrap form:not(:has(input[name="password"])) label:has(input[name="email"]) {
  position: relative;
  margin-bottom: 21px;
}

.auth-form-wrap form:not(:has(input[name="password"])) label:has(input[name="email"])::after {
  position: absolute;
  top: calc(100% + 5px);
  left: 1px;
  right: 0;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: 0;
  text-transform: none;
}

form[data-rp-email="bad"] label:has(input[name="email"])::after {
  content: "That is not a complete email address — it needs a name, an @, and a domain.";
  color: var(--rp-bad);
}
form[data-rp-email="checking"] label:has(input[name="email"])::after {
  content: "Checking that this address can receive mail…";
  color: var(--rp-note);
}
form[data-rp-email="unreachable"] label:has(input[name="email"])::after {
  content: "That domain cannot receive email, so a code could never arrive. Check the spelling.";
  color: var(--rp-bad);
}
/* No account. The refusal is the whole point of the check: nothing is sent to
   an address that has none, so saying so here is the only place it can be said. */
form[data-rp-email="none"] label:has(input[name="email"])::after {
  content: "There is no Senditto account for this address.";
  color: var(--rp-bad);
}
/* No account, and the domain is a known misspelling of a big provider — far and
   away the likeliest reason a real customer is told there is no account. The
   suggestion belongs beside the refusal, where it is actually useful. */
form[data-rp-email="none-typo"] label:has(input[name="email"])::after {
  content: "There is no Senditto account for this address. Did you mean " var(--rp-typo, "another domain") "?";
  color: var(--rp-bad);
}
form[data-rp-email="throttled"] label:has(input[name="email"])::after {
  content: "Too many checks from here. Please wait a few minutes and try again.";
  color: var(--rp-warn);
}
form[data-rp-email="ok"] label:has(input[name="email"])::after {
  content: "This account exists. We will email a code to it.";
  color: var(--rp-good);
}

/* The green circle with the check mark.
   One element: the circle is the background colour, the tick is an inline SVG
   sitting on top of it, so no second pseudo-element and no injected node. It is
   pinned to the bottom of the label because the input is the last thing in it,
   which keeps it centred on the field however tall the label's own text is. */
form[data-rp-email="ok"] label:has(input[name="email"])::before,
form[data-rp-email="none"] label:has(input[name="email"])::before,
form[data-rp-email="none-typo"] label:has(input[name="email"])::before {
  content: "";
  position: absolute;
  right: 13px;
  bottom: 13px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E")
      center / 11px 11px no-repeat,
    var(--rp-good);
  animation: rp-pop .22s ease-out;
}
/* A refusal gets its own mark rather than a tick recoloured: a cross and a check
   are told apart at a glance and by anybody who cannot separate red from green,
   which colour alone would leave guessing. */
form[data-rp-email="none"] label:has(input[name="email"])::before,
form[data-rp-email="none-typo"] label:has(input[name="email"])::before {
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.5' stroke-linecap='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E")
      center / 11px 11px no-repeat,
    var(--rp-bad);
}

@keyframes rp-pop {
  from { transform: scale(.4); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  form[data-rp-email] label:has(input[name="email"])::before { animation: none; }
}

/* The field's own border follows the verdict, so the answer is visible even
   with the message scrolled out of view. */
form[data-rp-email="none"] label:has(input[name="email"]) input,
form[data-rp-email="none-typo"] label:has(input[name="email"]) input,
form[data-rp-email="unreachable"] label:has(input[name="email"]) input {
  border-color: var(--rp-bad) !important;
}
form[data-rp-email="ok"] label:has(input[name="email"]) input {
  border-color: var(--rp-good) !important;
}

.auth-form-wrap form:not(:has(input[name="password"])) button[disabled],
.auth-form-wrap form:not(:has(input[name="password"])) .auth-primary[disabled] {
  opacity: .5;
  cursor: not-allowed;
  filter: grayscale(.35);
}

/* ── The panel ─────────────────────────────────────────────────────────── */
.rp-open { overflow: hidden; }

.rp-wrap {
  position: fixed;
  inset: 0;
  z-index: 2147483000;
  display: grid;
  place-items: center;
  padding: 20px;
  background: var(--rp-veil);
  backdrop-filter: blur(3px);
  overflow-y: auto;
  animation: rp-fade .16s ease-out;
}
@keyframes rp-fade { from { opacity: 0 } to { opacity: 1 } }

.rp-card {
  width: min(430px, 100%);
  box-sizing: border-box;
  padding: 26px 26px 22px;
  border-radius: 16px;
  border: 1px solid var(--rp-line);
  background: var(--rp-sheet);
  color: var(--rp-ink);
  box-shadow: 0 24px 60px rgba(8, 16, 32, .3);
  font: 400 14px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;
}

.rp-card > small {
  display: block;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .11em;
  color: var(--rp-note);
}
.rp-card h2 {
  margin: 7px 0 9px;
  font-size: 21px;
  line-height: 1.25;
  font-weight: 660;
  text-wrap: balance;
}
.rp-lede {
  margin: 0 0 17px;
  color: var(--rp-note);
  font-size: 13.5px;
}

.rp-field {
  display: block;
  position: relative;
  margin-bottom: 19px;
}
.rp-field > span {
  display: block;
  margin-bottom: 6px;
  font-size: 12px;
  font-weight: 620;
}
.rp-field input {
  box-sizing: border-box;
  width: 100%;
  padding: 11px 13px;
  border-radius: 10px;
  border: 1px solid var(--rp-line);
  background: transparent;
  color: inherit;
  font: inherit;
}
.rp-field input:focus-visible {
  /* Neutral on purpose. A green ring around a field whose message reads "these
     two do not match yet" tells two different stories at once. */
  outline: 2px solid #2563eb;
  outline-offset: 1px;
}
.rp-code {
  font-variant-numeric: tabular-nums;
  letter-spacing: .34em;
  font-size: 19px !important;
  text-align: center;
}

/* The message under a field, and the strength bar over it. Both sit outside
   the flow so nothing shifts as they appear and go. */
.rp-say {
  position: absolute;
  top: calc(100% + 4px);
  left: 1px;
  right: 0;
  font-size: 11.5px;
  font-style: normal;
  line-height: 1.35;
}
.rp-say[data-tone="bad"]  { color: var(--rp-bad); }
.rp-say[data-tone="warn"] { color: var(--rp-warn); }
.rp-say[data-tone="good"] { color: var(--rp-good); }

.rp-meter {
  position: absolute;
  top: calc(100% + 20px);
  left: 1px;
  right: 0;
  height: 3px;
  border-radius: 999px;
  background:
    linear-gradient(to right, var(--rp-fill, transparent) 0 var(--rp-at), transparent var(--rp-at) 100%),
    var(--rp-track);
  transition: --rp-at .18s ease;
}
.rp-meter[data-rate=""]        { opacity: 0; }
.rp-meter[data-rate="short"]   { --rp-fill: var(--rp-bad);  --rp-at: 18%; }
.rp-meter[data-rate="obvious"] { --rp-fill: var(--rp-bad);  --rp-at: 18%; }
.rp-meter[data-rate="weak"]    { --rp-fill: var(--rp-warn); --rp-at: 45%; }
.rp-meter[data-rate="fair"]    { --rp-fill: var(--rp-good); --rp-at: 72%; }
.rp-meter[data-rate="strong"]  { --rp-fill: var(--rp-good); --rp-at: 100%; }
/* Room for the bar as well as the sentence under the password field. At 26px
   the bar finished flush against the next label and read as its underline. */
.rp-field:has(.rp-meter) { margin-bottom: 34px; }

.rp-go {
  width: 100%;
  margin-top: 4px;
  padding: 12px 16px;
  border: 0;
  border-radius: 10px;
  background: #2563eb;
  color: #fff;
  font: 600 14px/1 system-ui, sans-serif;
  cursor: pointer;
}
.rp-go:hover:not([disabled]) { background: #1d4fd8; }
.rp-go[disabled] { opacity: .5; cursor: not-allowed; filter: grayscale(.35); }

.rp-more {
  display: flex;
  gap: 14px;
  justify-content: space-between;
  margin-top: 13px;
}
.rp-more button {
  padding: 0;
  border: 0;
  background: none;
  color: var(--rp-note);
  font: 500 12.5px/1.4 system-ui, sans-serif;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.rp-more button:hover:not([disabled]) { color: var(--rp-ink); }
.rp-more button[disabled] { opacity: .45; cursor: not-allowed; text-decoration: none; }

.rp-note {
  margin: 13px 0 0;
  min-height: 1.4em;
  font-size: 12.5px;
  color: var(--rp-note);
}
.rp-note[data-tone="bad"]  { color: var(--rp-bad); font-weight: 550; }
.rp-note[data-tone="good"] { color: var(--rp-good); font-weight: 550; }

.rp-small {
  margin: 12px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--rp-line);
  font-size: 11.5px;
  color: var(--rp-note);
}

/* The tick on the finished panel — the same circle, drawn larger. */
.rp-done {
  width: 46px;
  height: 46px;
  margin-bottom: 15px;
  border-radius: 50%;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E")
      center / 24px 24px no-repeat,
    var(--rp-good);
  animation: rp-pop .26s ease-out;
}
@media (prefers-reduced-motion: reduce) {
  .rp-wrap, .rp-done { animation: none; }
}

/* The button says "Send reset link", and a link is not what we send.
   Recovery is a six-digit code, and a button promising something else is how
   somebody ends up hunting an inbox for a link that was never there.
   The label is replaced in CSS rather than by rewriting the button's contents:
   this button belongs to React, and editing what is inside it is exactly the
   move that once left the application stuck on its loading skeleton. Collapsing
   the type hides the original text without removing the node; the arrow beside
   it is an SVG with its own dimensions and is unaffected. */
.auth-form-wrap form:not(:has(input[name="password"])) .auth-primary {
  font-size: 0;
}
.auth-form-wrap form:not(:has(input[name="password"])) .auth-primary::before {
  content: "Email me a code";
  font-size: 14px;
  font-weight: 600;
  letter-spacing: normal;
}
