/* ============================================================
   auth.css — MathematiX sign in / create account.
   Same quiet-laboratory aesthetic as the landing page:
   paper grid, emerald, Spectral headlines, mono chrome.
   ============================================================ */

.auth-body { min-height: 100vh; display: flex; flex-direction: column; overflow-x: hidden; }

/* the hidden attribute must always win over display rules below */
[hidden] { display: none !important; }

/* ---------- top bar ---------- */
.auth-top {
  display: flex; align-items: center; justify-content: space-between;
  padding: 22px 30px;
  position: relative; z-index: 5;
  animation: fade-down .6s var(--ease) both;
}
.auth-top .brand { display: inline-flex; align-items: center; gap: 11px; font-family: var(--font-serif); font-size: 1.28rem; font-weight: 500; letter-spacing: -0.02em; }
.auth-top .brand .x { color: var(--green); font-style: italic; }
.auth-top .brand__mark img { width: 26px; height: 26px; }
.auth-top__back {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.04em;
  color: var(--ink-soft);
  padding: 8px 14px; border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--paper-2);
  transition: color .2s var(--ease), border-color .2s var(--ease), transform .2s var(--ease);
}
.auth-top__back svg { width: 14px; height: 14px; transition: transform .25s var(--ease); }
.auth-top__back:hover { color: var(--green-700); border-color: var(--green-300); transform: translateY(-1px); }
.auth-top__back:hover svg { transform: translateX(3px); }

/* ---------- stage ---------- */
.auth-stage {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px;
  padding: 24px 20px 56px;
  position: relative; z-index: 4;
}

/* ---------- floating canvas boxes ----------
   Not decorative lookalikes: this is the app's own .box component,
   copied rule-for-rule from app.css (and the hero's math typesetting
   from hero-app.css) so the sign-in page shows the real notebook.
   Only the placement + entrance below is local to this page. */
.float-deck { position: fixed; inset: 0; z-index: 1; pointer-events: none; }

.box {
  position: absolute;
  box-sizing: border-box;
  background: var(--paper-3);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: var(--shadow-sm);
  user-select: none;
  display: flex;
  overflow: visible;
}
.box--text { overflow: visible; }
.box__content {
  flex: none; width: 100%;
  box-sizing: border-box;
  padding: 12px 14px;
  white-space: pre-wrap;
  font-family: var(--font-sans);
  font-size: 14px; line-height: 1.5; color: var(--ink);
  border-radius: 12px;
}
.box--math { align-items: center; justify-content: center; }
.box__math-display {
  width: 100%; text-align: center;
  padding: 9px 13px;
  color: var(--ink);
  white-space: nowrap;
  font-size: 15px;
}

/* math typesetting — the app renders this with KaTeX; the marketing pages
   mirror it in plain markup rather than pulling KaTeX (and a CSP exception)
   onto a page that only needs four static equations. Same rules as hero-app.css. */
.m { font-family: var(--font-serif); font-style: italic; letter-spacing: .01em; }
.m .up { font-style: normal; }
.m .op { font-style: normal; color: var(--ink); padding: 0 .16em; }
.m .int { font-style: normal; font-size: 1.5em; line-height: 0; vertical-align: -0.18em; padding-right: .06em; }
.m sup { font-size: .68em; vertical-align: .48em; line-height: 0; }
.m sub { font-size: .68em; vertical-align: -.22em; line-height: 0; }
.m .thin { display: inline-block; width: .18em; }

/* graph box — head + canvas, straight from app.css */
.box--graph { flex-direction: column; overflow: visible; }
.box__graph-head {
  flex: none; display: flex; align-items: center; gap: 6px;
  padding: 7px 9px; border-bottom: 1px solid var(--line-soft);
  font-family: var(--font-mono); font-size: 11px; color: var(--ink-faint);
}
.box__graph-head .g-math {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; min-height: 22px; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--paper-2); color: var(--ink);
  padding: 2px 6px; overflow: hidden;
}
.box__graph-head .g-fn { flex: 1; min-width: 0; }
.box__graph-head .g-math__display { white-space: nowrap; }
.box__graph-head .g-range { display: inline-flex; align-items: center; gap: 2px; }
.box__graph-canvas { flex: 1; width: 100%; display: block; border-radius: 0 0 12px 12px; }
/* the plot colours graph.js paints onto the real canvas */
.fg-grid line { stroke: rgba(22,32,26,0.07); stroke-width: 1; }
.fg-axis line { stroke: rgba(22,32,26,0.4); stroke-width: 1; }
.fg-curve { stroke: var(--green); stroke-width: 2; }
.fg-tip { fill: var(--green); }

/* ---------- placement + entrance (local to this page) ---------- */
.fbox {
  opacity: 0;
  animation: box-in .52s cubic-bezier(.22,1.2,.36,1) both, bob 7s ease-in-out infinite;
}
.fbox--eq    { top: 17%; left: 7%;   width: max-content; animation-delay: .35s, 0s; }
.fbox--note  { top: 20%; right: 7%;  width: 244px; animation-delay: .45s, .8s; }
.fbox--graph { bottom: 16%; left: 9%; width: 218px; height: 138px; animation-delay: .55s, 1.4s; }
.fbox--chem  { bottom: 21%; right: 9%; width: max-content; animation-delay: .65s, 2.1s; }

/* the app's own spawn animation (app.css .box--spawn) */
@keyframes box-in {
  from { opacity: 0; transform: scale(0.9) translateY(8px); }
  60%  { opacity: 1; }
  to   { opacity: 1; transform: none; }
}
@keyframes bob { 0%,100% { translate: 0 0; } 50% { translate: 0 -10px; } }
@keyframes draw-line { to { stroke-dashoffset: 0; } }
@keyframes fade-down { from { opacity: 0; transform: translateY(-14px); } to { opacity: 1; transform: none; } }
@keyframes fade-up { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }

.fg-curve { stroke-dasharray: 260; stroke-dashoffset: 260; animation: draw-line 1.6s var(--ease) 1s forwards; }
.fg-tip { offset-path: path("M18 100 Q109 -40 200 100"); animation: ride 5s ease-in-out 1.3s infinite alternate; }
@keyframes ride { from { offset-distance: 0%; } to { offset-distance: 100%; } }

/* ---------- card ---------- */
.auth-card {
  width: 100%; max-width: 430px;
  background: var(--paper-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 26px 30px 24px;
  position: relative;
  animation: fade-up .7s var(--ease) .15s both;
}
.auth-card.is-shake { animation: shake .45s var(--ease); }
@keyframes shake {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(4px); }
  30%, 70% { transform: translateX(-6px); }
  40%, 60% { transform: translateX(6px); }
  50% { transform: translateX(-4px); }
}

/* ---------- mode toggle ---------- */
.mode {
  position: relative;
  display: grid; grid-template-columns: 1fr 1fr;
  background: var(--paper);
  border: 1px solid var(--line-soft);
  border-radius: 12px;
  padding: 4px;
  margin-bottom: 22px;
}
.mode__pill {
  position: absolute; top: 4px; bottom: 4px; left: 4px;
  width: calc(50% - 4px);
  background: var(--paper-3);
  border: 1px solid var(--line);
  border-radius: 9px;
  box-shadow: var(--shadow-sm);
  transition: transform .3s var(--ease);
}
.mode[data-mode="signup"] .mode__pill { transform: translateX(100%); }
.mode__opt {
  position: relative; z-index: 1;
  padding: 9px 6px;
  font-weight: 600; font-size: 0.92rem;
  color: var(--ink-faint);
  transition: color .25s var(--ease);
  border-radius: 9px;
}
.mode__opt.is-on { color: var(--ink); }
.mode__opt:hover:not(.is-on) { color: var(--ink-soft); }

/* ---------- headings ---------- */
.auth-head { margin-bottom: 18px; }
.auth-title { font-size: 1.85rem; font-weight: 500; }
.auth-sub { color: var(--ink-soft); font-size: 0.95rem; margin-top: 6px; }

/* mode crossfade */
.auth-head, .auth-form, .auth-foot { transition: opacity .22s var(--ease), transform .22s var(--ease); }
.is-swapping .auth-head, .is-swapping .auth-form, .is-swapping .auth-foot { opacity: 0; transform: translateY(6px); }

/* ---------- error banner ---------- */
.auth-error {
  display: flex; align-items: flex-start; gap: 9px;
  background: rgba(179,70,60,0.08);
  border: 1px solid rgba(179,70,60,0.25);
  color: #8c3128;
  border-radius: 12px;
  padding: 11px 13px;
  font-size: 0.88rem; line-height: 1.45;
  margin-bottom: 16px;
  animation: fade-up .3s var(--ease);
}
.auth-error svg { width: 16px; height: 16px; flex: none; margin-top: 2px; }

/* Quiet counterpart to .auth-error: "you're already signed in", shown when
   Get Started brings a live session to the create-account form. */
.auth-note {
  display: flex; align-items: center; gap: 9px;
  background: var(--mint);
  border: 1px solid var(--mint-line);
  color: var(--green-800);
  border-radius: 12px;
  padding: 10px 12px;
  font-size: 0.85rem; line-height: 1.45;
  margin-bottom: 16px;
  animation: fade-up .3s var(--ease);
}
.auth-note svg { width: 16px; height: 16px; flex: none; }
.auth-note__txt { flex: 1; min-width: 0; }
.auth-note__txt b { font-weight: 600; }
.auth-note__go {
  flex: none;
  font-family: var(--font-mono); font-size: 11px; font-weight: 500;
  color: var(--green-700);
  text-decoration: underline; text-underline-offset: 3px;
  white-space: nowrap;
}
.auth-note__go:hover { color: var(--green-800); }

/* ---------- fields ----------
   Same input language as the marketing signup field (.signup__field):
   white paper, hairline rule, 12px radius, accent-tinted mint focus ring.
   Everything here keys off --green-300 / --mint so the four accent
   palettes recolour the form for free. */
.auth-form { display: flex; flex-direction: column; gap: 16px; }
.field { position: relative; }
.field__label {
  display: block;
  font-size: 0.84rem; font-weight: 600; letter-spacing: 0.005em;
  color: var(--ink-soft);
  margin-bottom: 8px;
  transition: color .22s var(--ease);
}
.field:focus-within .field__label { color: var(--green-700); }
.field__labelrow { display: flex; align-items: baseline; justify-content: space-between; }
.field__labelrow .field__label { margin-bottom: 8px; }
.field__forgot {
  font-size: 0.8rem; color: var(--green-700); font-weight: 500;
  transition: opacity .2s var(--ease);
}
.field__forgot:hover { text-decoration: underline; text-underline-offset: 2px; }

.field__box {
  position: relative;
  display: flex; align-items: center; gap: 11px;
  background: var(--paper-3);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 0 14px;
  height: 50px;
  box-shadow: var(--shadow-sm);
  transition: border-color .22s var(--ease), box-shadow .22s var(--ease),
              transform .22s var(--ease);
}
/* the sweep: a single soft mint pass across the field the moment it
   takes focus. Lives under the text on its own layer so it never
   repaints the caret. */
.field__box::before {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(100deg,
    transparent 20%, var(--mint) 48%, transparent 76%);
  background-size: 220% 100%;
  background-position: 100% 0;
}
.field__box:focus-within::before { animation: field-sweep .85s var(--ease); }
@keyframes field-sweep {
  0%   { opacity: 0;   background-position: 100% 0; }
  35%  { opacity: .85; }
  100% { opacity: 0;   background-position: 0% 0; }
}
.field__box:hover { border-color: var(--mint-line); box-shadow: var(--shadow-md); }
.field__box:focus-within {
  border-color: var(--green-300);
  box-shadow: 0 0 0 4px var(--mint), var(--shadow-md);
  transform: translateY(-1px);
}
/* a field the user has already filled keeps a slightly firmer rule */
.field__box:has(input:not(:placeholder-shown)):not(:focus-within) { border-color: var(--mint-line); }

.field__ic {
  width: 17px; height: 17px; flex: none;
  color: var(--ink-faint);
  position: relative; z-index: 1;
  transition: color .22s var(--ease), transform .3s var(--ease);
}
.field__box:focus-within .field__ic { color: var(--green-700); transform: scale(1.08); }

.field__box input {
  flex: 1; min-width: 0; height: 100%;
  border: none; outline: none; background: transparent;
  font-family: var(--font-sans); font-size: 0.97rem; color: var(--ink);
  caret-color: var(--green);
  position: relative; z-index: 1;
}
.field__box input::placeholder {
  color: var(--ink-faint);
  transition: color .22s var(--ease), opacity .22s var(--ease), transform .22s var(--ease);
}
.field__box:focus-within input::placeholder { opacity: .55; transform: translateX(2px); }
/* Chrome's autofill wash would repaint the field pale blue — hold the paper */
.field__box input:-webkit-autofill,
.field__box input:-webkit-autofill:hover,
.field__box input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--ink);
  -webkit-box-shadow: 0 0 0 40px var(--paper-3) inset;
  caret-color: var(--green);
  transition: background-color 9999s ease-in-out 0s;
}

.field__hint {
  font-size: 0.78rem; color: var(--ink-faint); margin-top: 7px;
  font-family: var(--font-mono);
  transition: color .22s var(--ease);
}
.field__hint.is-bad { color: #8c3128; }
.field__hint.is-good { color: var(--green-700); }

/* username live status */
.field__status { width: 18px; height: 18px; flex: none; position: relative; z-index: 1; }
.field__status[data-state="checking"]::after {
  content: ""; position: absolute; inset: 1px;
  border: 2px solid var(--line); border-top-color: var(--green);
  border-radius: 50%; animation: spin 0.7s linear infinite;
}
.field__status[data-state="good"]::after {
  content: "✓"; position: absolute; inset: 0;
  color: var(--green-700); font-weight: 700; font-size: 14px; line-height: 18px; text-align: center;
  animation: pop-in .25s var(--ease);
}
.field__status[data-state="bad"]::after {
  content: "✕"; position: absolute; inset: 0;
  color: #b3463c; font-weight: 700; font-size: 13px; line-height: 18px; text-align: center;
  animation: pop-in .25s var(--ease);
}
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes pop-in { from { transform: scale(.4); opacity: 0; } to { transform: scale(1); opacity: 1; } }

/* password eye */
.field__eye {
  flex: none; width: 30px; height: 30px;
  display: grid; place-items: center;
  color: var(--ink-faint); border-radius: 8px;
  position: relative; z-index: 1;
  transition: color .2s var(--ease), background .2s var(--ease), transform .2s var(--ease);
}
.field__eye:hover { color: var(--green-700); background: var(--mint); }
.field__eye:active { transform: scale(.9); }
.field__eye svg { width: 17px; height: 17px; }

/* password strength */
.pwmeter { display: flex; align-items: center; gap: 10px; margin-top: 9px; }
.pwmeter__track { flex: 1; height: 4px; border-radius: 99px; background: var(--line-soft); overflow: hidden; }
.pwmeter__bar { display: block; height: 100%; width: 0; border-radius: 99px; background: #b3463c; transition: width .35s var(--ease), background .35s var(--ease); }
.pwmeter__label { font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-faint); min-width: 64px; text-align: right; }

/* ---------- terms checkbox ---------- */
.terms { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; user-select: none; padding: 2px 0; }
.terms input { position: absolute; opacity: 0; pointer-events: none; }
.terms__box {
  width: 20px; height: 20px; flex: none; margin-top: 1px;
  border: 1.5px solid var(--line);
  border-radius: 6px;
  background: var(--paper-2);
  display: grid; place-items: center;
  transition: background .2s var(--ease), border-color .2s var(--ease), transform .15s var(--ease);
}
.terms__box svg { width: 12px; height: 12px; color: #fff; opacity: 0; transform: scale(.4); transition: opacity .18s var(--ease), transform .18s var(--ease); }
.terms input:checked + .terms__box { background: var(--green); border-color: var(--green); }
.terms input:checked + .terms__box svg { opacity: 1; transform: scale(1); }
.terms input:focus-visible + .terms__box { box-shadow: 0 0 0 4px var(--mint); }
.terms:active .terms__box { transform: scale(.92); }
.terms__txt { font-size: 0.85rem; color: var(--ink-soft); line-height: 1.5; }
.terms__txt a { color: var(--green-700); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
.terms.is-missing .terms__box { border-color: #b3463c; animation: shake .4s var(--ease); }

/* ---------- submit ---------- */
.auth-submit { height: 50px; font-size: 1rem; margin-top: 4px; }
.auth-submit[disabled] { opacity: .65; cursor: not-allowed; transform: none !important; }
.auth-spinner {
  width: 17px; height: 17px;
  border: 2px solid rgba(255,255,255,0.4); border-top-color: #fff;
  border-radius: 50%;
  animation: spin .7s linear infinite;
}

/* ---------- card footer ---------- */
.auth-foot { text-align: center; font-size: 0.88rem; color: var(--ink-soft); margin-top: 18px; }
.auth-foot button { color: var(--green-700); font-weight: 600; font-size: inherit; }
.auth-foot button:hover { text-decoration: underline; }
.auth-legal { font-family: var(--font-mono); font-size: 11px; color: var(--ink-faint); animation: fade-up .7s var(--ease) .4s both; }
.auth-legal a { text-decoration: underline; text-underline-offset: 2px; }
.auth-legal a:hover { color: var(--green-700); }

/* ---------- verification code panel ---------- */
.verify-mark {
  display: inline-grid; place-items: center;
  width: 56px; height: 56px;
  border-radius: 16px;
  background: var(--mint); border: 1px solid var(--mint-line);
  color: var(--green-700);
  margin-bottom: 14px;
  animation: pop-in .4s var(--ease) .15s both;
}
.verify-mark svg { width: 26px; height: 26px; }
.code {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  margin: 20px 0 18px;
}
.code input {
  width: 42px; height: 52px;
  text-align: center;
  font-family: var(--font-mono); font-size: 1.28rem; font-weight: 500;
  color: var(--ink);
  background: var(--paper-3);
  border: 1px solid var(--line);
  border-radius: 12px;
  outline: none;
  box-shadow: var(--shadow-sm);
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease),
              transform .18s var(--ease);
  caret-color: var(--green);
}
.code input:hover { border-color: var(--mint-line); }
.code input:focus {
  border-color: var(--green-300);
  box-shadow: 0 0 0 4px var(--mint), var(--shadow-md);
  transform: translateY(-2px);
}
.code input.is-filled {
  border-color: var(--green-300);
  animation: code-pop .22s var(--ease);
}
@keyframes code-pop { from { transform: scale(.9); } to { transform: none; } }
.code.is-bad input { border-color: rgba(179,70,60,0.55); box-shadow: var(--shadow-sm); animation: shake .4s var(--ease); }
.code__dash { color: var(--ink-faint); font-family: var(--font-mono); }
.verify-resend button[disabled] { color: var(--ink-faint); cursor: default; text-decoration: none !important; }
@media (max-width: 520px) {
  .code { gap: 5px; }
  .code input { width: 34px; height: 44px; font-size: 1.1rem; }
}

/* ---------- success panel ---------- */
.auth-card--success { text-align: center; padding-top: 36px; }
.auth-card--success .auth-sub { margin: 10px auto 22px; max-width: 32ch; }
.auth-card--success .btn { margin-bottom: 4px; }
.success-ring { display: inline-block; width: 64px; height: 64px; margin-bottom: 14px; }
.success-ring .ring {
  stroke: var(--green); stroke-width: 2.5;
  stroke-dasharray: 151; stroke-dashoffset: 151;
  animation: draw-line .7s var(--ease) .1s forwards;
}
.success-ring .tick {
  stroke: var(--green); stroke-width: 3.4; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 36; stroke-dashoffset: 36;
  animation: draw-line .45s var(--ease) .65s forwards;
}

/* ---------- responsive / motion ---------- */
@media (max-width: 1100px) {
  .fbox--eq { left: 2%; } .fbox--note { right: 2%; }
  .fbox--graph { left: 3%; } .fbox--chem { right: 3%; }
}
@media (max-width: 860px) { .float-deck { display: none; } }
@media (max-width: 520px) {
  .auth-card { padding: 22px 20px 20px; border-radius: 20px; }
  .auth-top { padding: 16px 18px; }
  .auth-top__back span { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}

/* ============ on-screen keyboard ============
   assets/js/keyboard-inset.js publishes --kb-inset: the part of the
   keyboard the browser did NOT take off the viewport by itself. It is
   0 in Safari and Chrome, which shrink the viewport and scroll the
   focused field into view on their own, and it is the whole keyboard
   inside an in-app WebView (Instagram, Facebook, TikTok), which reports
   nothing at all and lets the keys land on top of the form.

   Reserving that height at the foot of the page does two things: the
   centred card is centred in what is actually visible, and the field
   has somewhere to scroll to — which is where the script puts it. */
body.kb-open { padding-bottom: var(--kb-inset, 0px); }
body.kb-open .auth-stage { justify-content: flex-start; }

