/* Created: 17:50 29-Aug-2026 */
/* Updated: 20:05 29-Aug-2026 — 44px audit: the code field had no [type] so it missed the rule */
/* The sign-in and sign-up pages. Shared by /login and /signup, which are the same two steps
   with different words around them.

   TOKENS ARE COPIED FROM v3.css DELIBERATELY, not imported. These pages must render before any
   module loads and must not depend on the app shell they lead into — a sign-in screen that is
   blank because the app's stylesheet 404'd is the worst possible failure. The values are the
   contract; if v3's palette changes, change both. */

:root{
  --bg:#fffdf5; --fg:#1c1a12; --muted:#6b6450;
  --accent:#ffd83d; --btn-bg:#111; --btn-fg:#ffd83d;
  --field-bg:#fff6d6; --border:rgba(60,50,10,.14); --rule:rgba(60,50,10,.09);
  --panel:#fff; --err:#a3341f; --errbg:#fdeeea;
  --sans:-apple-system,BlinkMacSystemFont,'Segoe UI',Inter,Roboto,Helvetica,Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}

/* THE GLOBAL REDUCED-MOTION RESET. A11y §28 / Tokens §22, and it was measured at ZERO
   occurrences across the whole app on 29-Aug-2026.

   `!important` and the near-zero durations rather than `none`: a duration of 0 still FIRES
   transitionend and animationend, so any script waiting on one keeps working. `animation:none`
   silently strands that listener, and the bug looks like "the button never re-enables". */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important; animation-iteration-count:1 !important;
    transition-duration:.01ms !important; scroll-behavior:auto !important;
  }
}

*{box-sizing:border-box}
body{
  margin:0;background:#f4f1e6;color:var(--fg);font:15px/1.6 var(--sans);
  -webkit-font-smoothing:antialiased;
  min-height:100vh;display:flex;flex-direction:column;
}

/* SKIP LINK — the first focusable element on the page, targeting <main>. A11y §4, INVARIANT,
   and it was absent from every surface. Visible only on focus, but never `display:none` when
   unfocused: a display:none element is not focusable at all, so the link would not exist for
   the keyboard user it is for. Moved off-screen instead. */
.skip{
  position:absolute;left:-9999px;top:0;z-index:100;
  background:var(--btn-bg);color:var(--btn-fg);padding:12px 18px;border-radius:0 0 10px 0;
  font-weight:700;text-decoration:none;
}
.skip:focus{left:0}

/* VISIBLE FOCUS, everywhere, on one rule. `:focus-visible` rather than `:focus` so a mouse
   click on a button does not leave a ring behind it, while every keyboard path shows one.
   The outline is offset so it never sits on the control's own border and read as a bug. */
:focus-visible{outline:3px solid #2b6cb0;outline-offset:2px;border-radius:4px}

header.bar{padding:22px 20px 0;display:flex;justify-content:center}
.brand{
  /* 44px floor: it is a link to the marketing site, so it is a real target, not decoration.
     Measured at 156x32 before this line. */
  min-height:44px;
  display:flex;align-items:center;gap:10px;font-weight:800;font-size:17.5px;
  letter-spacing:-.02em;text-decoration:none;color:var(--fg);
}
/* The mark, matching the marketing site and the app's top bar. One shape, three surfaces. */
.brand .mark{
  width:32px;height:32px;border-radius:9px;background:var(--accent);
  display:grid;place-items:center;font-size:18px;line-height:1;
  box-shadow:0 1px 0 rgba(60,50,10,.14);
}

main{flex:1;display:flex;align-items:center;justify-content:center;padding:26px 18px 40px}
.card{
  width:100%;max-width:404px;background:var(--panel);border:1px solid var(--border);
  border-radius:16px;padding:28px 26px 24px;box-shadow:0 8px 30px rgba(60,50,10,.07);
}
h1{font-size:22px;line-height:1.25;margin:0 0 6px;letter-spacing:-.01em}
.sub{color:var(--muted);font-size:14px;margin:0 0 20px}

label{display:block;font-weight:650;font-size:13.5px;margin:0 0 6px}
/* `input:not([type])` is load-bearing, not defensive. The 4-digit code field carries
   inputmode but NO type attribute, so `input[type=text]` never matched it — MEASURED in Chrome
   at 313x34 against a 44px floor while every other field was 46. An attribute selector does not
   match a missing attribute, and nothing about the rendered page said so. */
input[type=email],input[type=text],input:not([type]){
  width:100%;background:var(--field-bg);border:1px solid var(--border);border-radius:10px;
  padding:0 13px;font:15px var(--sans);color:var(--fg);
  /* 46px, above the 44x44 floor (A11y §22 / Mobile §6). Audited rather than assumed: every
     interactive control on these two pages was measured, and the numbers are in NOTES.md. */
  height:46px;
}
input:focus{background:#fff}
input[aria-invalid="true"]{border-color:var(--err);background:var(--errbg)}

.code-in{
  font:650 24px/1 var(--mono);letter-spacing:.42em;text-align:center;
  padding-left:.42em;  /* letter-spacing adds a trailing gap; this re-centres the digits */
}

button{
  width:100%;min-height:46px;border:0;border-radius:11px;cursor:pointer;
  background:var(--btn-bg);color:var(--btn-fg);font:700 15px var(--sans);
  transition:opacity .12s ease;
}
button:hover:not(:disabled){opacity:.9}
button:disabled{opacity:.42;cursor:not-allowed}
button.sec{background:transparent;color:var(--fg);border:1px solid var(--border);font-weight:600}
.row{display:flex;gap:9px;margin-top:9px}
.row button{flex:1}

.terms{
  display:flex;gap:10px;align-items:flex-start;margin:16px 0 0;
  font-weight:400;font-size:13.5px;color:var(--muted);cursor:pointer;line-height:1.5;
  /* The whole line is the label, so the tap target is the sentence and not just the 16px box —
     which is what keeps this above the 44px floor without drawing a 44px checkbox. */
  min-height:44px;padding:4px 0;
}
.terms input{width:18px;height:18px;margin:2px 0 0;flex:none;accent-color:var(--btn-bg)}
.terms a{color:var(--fg)}

/* THE HONEYPOT. Hidden from sight AND from assistive technology, which is why it carries
   aria-hidden, tabindex=-1 and autocomplete=off together — a field hidden only visually is one
   a screen-reader user will be asked to fill in, and they will fail the check a bot was meant
   to fail. NOT `display:none`: some bots skip those on the reasonable assumption they are traps.
   The name is plausible on purpose; `hp_` would be read by anything that looks. */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

.msg{min-height:20px;margin:14px 0 0;font-size:13.5px;color:var(--err)}
.msg.info{color:var(--muted)}
.alt{margin:18px 0 0;padding-top:16px;border-top:1px solid var(--rule);
     font-size:13.5px;color:var(--muted);text-align:center}
.alt a{color:var(--fg);font-weight:650}
.sent{font-size:13.5px;color:var(--muted);margin:0 0 16px}
.sent b{color:var(--fg)}

details.dev{margin-top:14px;font-size:13px;color:var(--muted)}
details.dev summary{cursor:pointer;min-height:44px;display:flex;align-items:center}
details.dev input{margin-bottom:9px}
details.dev code{font:12.5px var(--mono);background:var(--field-bg);padding:1px 5px;border-radius:5px}

@media (max-width:420px){
  .card{padding:22px 18px 20px}
  h1{font-size:20px}
}
