/* Sign-in page.
 *
 * Its own stylesheet and its own palette, deliberately separate from app.css.
 * The application's tokens describe a dense working surface -- warm paper,
 * IBM Plex, a teal that means "checked" -- and this page has one job before
 * any of that exists. It follows the sign-in design supplied for it: a cool
 * blue-cyan field, Manrope and Space Grotesk, a single card on a drifting
 * knowledge graph.
 *
 * Light only, with no dark variant, for the same reason: one screen, one
 * composition, and a card whose whole effect is a pale field lifting away from
 * a paler one.
 */

:root {
  --background: oklch(0.982 0.008 220);
  --foreground: oklch(0.205 0.035 246);
  --muted-fg: oklch(0.505 0.035 245);
  --surface: oklch(0.974 0.012 215);
  --surface-raised: oklch(1 0 0);
  --border: oklch(0.888 0.018 220);
  --input-border: oklch(0.885 0.02 220);
  --brand: oklch(0.45 0.12 210);
  --brand-strong: oklch(0.35 0.1 228);
  --brand-soft: oklch(0.92 0.045 196);
  --accent: oklch(0.94 0.035 190);
  --graph: oklch(0.56 0.09 205);
  --success: oklch(0.52 0.12 165);
  --destructive: oklch(0.57 0.19 25);
  --ring: oklch(0.62 0.12 205);

  --shadow-login:
    0 22px 70px -34px oklch(0.26 0.08 240 / 0.32),
    0 2px 8px oklch(0.25 0.06 240 / 0.05);
  --gradient-page: linear-gradient(
    128deg,
    oklch(0.982 0.008 220) 0%,
    oklch(0.98 0.012 198) 52%,
    oklch(0.956 0.026 188) 100%
  );

  --font-sans: "Manrope", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-display: "Space Grotesk", ui-sans-serif, system-ui, "Segoe UI", sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-sans);
  color: var(--foreground);
  background: var(--background);
  -webkit-font-smoothing: antialiased;
}

/* --- canvas ------------------------------------------------------------ */

.login-canvas {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  justify-content: center;
  /* dvh, not vh: on mobile Safari the toolbar makes 100vh taller than the
     visible area, which pushes a vertically centred card off centre. */
  min-height: 100dvh;
  overflow: hidden;
  padding: 2.5rem 1.25rem;
  background-image: var(--gradient-page);
}
@media (min-width: 640px) {
  .login-canvas { padding-inline: 2rem; }
}

.login-backdrop {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

.login-graph {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 150%;
  height: 125%;
  transform: translate(-50%, -50%);
  color: var(--graph);
  opacity: .13;
  animation: login-graph-drift 24s ease-in-out infinite alternate;
}
@media (min-width: 640px) {
  .login-graph { width: 120%; height: 115%; }
}
.login-graph-edges line { stroke: currentColor; stroke-width: 1; }
.login-graph-nodes circle { fill: currentColor; }
.login-graph-nodes .halo {
  fill: none;
  stroke: currentColor;
  stroke-width: 1;
  opacity: .4;
}
.login-graph-nodes .is-pulse { animation: login-node-pulse 4.5s ease-in-out infinite; }

/* Two soft lights, one warm-side, one cool-side, so the field is not flat. */
.login-glow {
  position: absolute;
  border-radius: 999px;
  filter: blur(48px);
}
.login-glow-brand {
  left: 8%;
  top: 18%;
  width: 10rem;
  height: 10rem;
  background: color-mix(in oklab, var(--brand-soft) 35%, transparent);
}
.login-glow-accent {
  right: 7%;
  bottom: 14%;
  width: 12rem;
  height: 12rem;
  background: color-mix(in oklab, var(--accent) 30%, transparent);
}

/* --- card -------------------------------------------------------------- */

.login-stack {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 430px;
  animation: login-card-enter 700ms cubic-bezier(.22, 1, .36, 1) both;
}

/* The wordmark, above the card. Sized by height so a wider or narrower
   lockup keeps the same optical weight. */
.login-brand {
  display: block;
  margin: 0 auto 1.5rem;
  width: fit-content;
}
.login-brand img {
  display: block;
  height: 34px; width: auto; max-width: 100%;
}
@media (max-width: 30rem) {
  .login-brand img { height: 28px; }
}

.login-eyebrow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .625rem;
  margin: 0 0 1.75rem;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--brand-strong) 70%, transparent);
}
.login-eyebrow span {
  width: 1.75rem;
  height: 1px;
  background: color-mix(in oklab, var(--brand) 25%, transparent);
}

.login-card {
  padding: 1.75rem;
  border: 1px solid color-mix(in oklab, var(--border) 80%, transparent);
  border-radius: 22px;
  background: color-mix(in oklab, var(--surface-raised) 90%, transparent);
  box-shadow: var(--shadow-login);
  backdrop-filter: blur(16px);
}
@media (min-width: 640px) {
  .login-card { padding: 2.25rem; }
}

.login-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  margin-bottom: 2rem;
}
.login-mark {
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  margin-bottom: 1.25rem;
  border: 1px solid color-mix(in oklab, var(--brand) 20%, transparent);
  border-radius: 16px;
  background: color-mix(in oklab, var(--brand-soft) 65%, transparent);
  color: var(--brand-strong);
  box-shadow: 0 1px 2px oklch(0.25 0.06 240 / .06);
}
.login-mark svg { width: 1.75rem; height: 1.75rem; }
.login-head h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.65rem;
  font-weight: 600;
  letter-spacing: -.03em;
}
.login-head p {
  margin: .5rem 0 0;
  font-size: .875rem;
  color: var(--muted-fg);
}

/* --- form -------------------------------------------------------------- */

.login-form { display: grid; gap: 1.25rem; }

/* `min-width: 0` on both, and it is load-bearing rather than defensive.

   A grid or flex item defaults to `min-width: auto`, meaning it will not
   shrink below its content's *intrinsic* width. For `.login-input` that
   intrinsic width is ~225px: an `<input>` with no `size` attribute reports a
   20-character default (~165px here), plus the icon, its margin, the wrapper
   padding and the border. A full-width field never notices, because its track
   is wider than that anyway -- but the two-column `.login-row` gives each cell
   a 201px track, and the cell then overflowed the card by 23px instead of
   shrinking to fit.

   The `min-width: 0` already on `.login-input input` is not enough on its own:
   it lets the input shrink *during* flex layout, while the wrapper's
   min-content contribution is still computed from the input's intrinsic size.
   The clamp has to be on the boxes that sit in the tracks. */
.login-field { display: grid; gap: .5rem; min-width: 0; }
.login-input { min-width: 0; }
.login-field label {
  font-size: .875rem;
  font-weight: 600;
}

/* The border and focus ring live on the wrapper, not the input: the icon and
   the reveal button sit inside the same box, and a ring drawn on the input
   alone would cut through both. */
.login-input {
  display: flex;
  align-items: center;
  height: 3rem;
  padding-inline: .875rem;
  border: 1px solid var(--input-border);
  border-radius: 12px;
  background: var(--surface);
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
.login-input:focus-within {
  border-color: var(--brand);
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--brand) 10%, transparent);
}
.login-input.is-invalid {
  border-color: color-mix(in oklab, var(--destructive) 70%, transparent);
}
.login-input-icon {
  width: 18px;
  height: 18px;
  margin-right: .75rem;
  flex: 0 0 auto;
  color: var(--muted-fg);
  transition: color 150ms ease;
}
.login-input:focus-within .login-input-icon { color: var(--brand); }
.login-input input {
  flex: 1;
  min-width: 0;
  height: 100%;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: .875rem;
  color: var(--foreground);
}
.login-input input:focus { outline: none; }
.login-input input::placeholder {
  color: color-mix(in oklab, var(--muted-fg) 70%, transparent);
}

.login-reveal {
  display: grid;
  place-items: center;
  padding: .375rem;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--muted-fg);
  cursor: pointer;
  transition: background-color 150ms ease, color 150ms ease;
}
.login-reveal:hover {
  background: var(--accent);
  color: var(--brand-strong);
}
.login-reveal svg { width: 17px; height: 17px; }
/* The UA's `[hidden] { display: none }` rule is scoped to the HTML namespace,
   so an SVG carrying the attribute still paints -- which stacked the eye and
   the crossed-out eye on top of each other. */
.login-reveal svg[hidden] { display: none; }

.login-error {
  margin: 0;
  font-size: .75rem;
  font-weight: 500;
  color: var(--destructive);
}

.login-forgot { display: flex; justify-content: flex-end; }
.login-forgot button {
  padding: 0;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: .75rem;
  font-weight: 600;
  color: var(--brand-strong);
  cursor: pointer;
  text-underline-offset: 4px;
}
.login-forgot button:hover { color: var(--brand); text-decoration: underline; }

.login-submit {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  width: 100%;
  height: 3rem;
  border: 0;
  border-radius: 12px;
  background: var(--brand-strong);
  color: oklch(0.985 0.008 220);
  font: inherit;
  font-size: .875rem;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 1px 2px oklch(0.25 0.06 240 / .08);
  transition: transform 150ms ease, background-color 150ms ease, box-shadow 150ms ease;
}
.login-submit svg { width: 1rem; height: 1rem; }
.login-submit:hover {
  transform: translateY(-1px);
  background: color-mix(in oklab, var(--brand-strong) 90%, transparent);
  box-shadow: 0 4px 12px oklch(0.25 0.06 240 / .12);
}
.login-submit:active { transform: none; }

.login-alert {
  display: flex;
  align-items: flex-start;
  gap: .625rem;
  margin: 0;
  padding: .75rem .875rem;
  border: 1px solid color-mix(in oklab, var(--destructive) 20%, transparent);
  border-radius: 12px;
  background: color-mix(in oklab, var(--destructive) 5%, transparent);
  font-size: .75rem;
  line-height: 1.45;
  color: var(--destructive);
}
.login-alert svg { width: 1rem; height: 1rem; flex: 0 0 auto; margin-top: .1rem; }

.login-note {
  margin: 0;
  padding: .75rem .875rem;
  border: 1px solid color-mix(in oklab, var(--brand) 20%, transparent);
  border-radius: 12px;
  background: color-mix(in oklab, var(--brand-soft) 45%, transparent);
  font-size: .75rem;
  line-height: 1.45;
  color: var(--brand-strong);
}

.login-foot {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  margin: 1.75rem 0 0;
  font-size: .625rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--muted-fg) 80%, transparent);
}
.login-dot {
  width: .375rem;
  height: .375rem;
  border-radius: 999px;
  background: var(--success);
}

.login-trust {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  margin: 1.5rem 0 0;
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .01em;
  color: var(--muted-fg);
}
.login-trust svg { width: .875rem; height: .875rem; color: var(--success); }

/* --- signup + expired --------------------------------------------------

   Both pages reuse the login card wholesale; what follows is only what they
   add to it. Kept in this file rather than a second stylesheet because the
   three pages share every token above and a split would duplicate all of it.
   ---------------------------------------------------------------------- */

/* Signup carries four more fields than login, so its column is wider. The
   card itself is unchanged -- only the track it sits in. */
.login-stack.is-wide { max-width: 30rem; }

.login-perks {
  display: grid;
  gap: .625rem;
  margin: 0 0 1.5rem;
  padding: 1rem 1.125rem;
  list-style: none;
  border: 1px solid color-mix(in oklab, var(--brand) 14%, transparent);
  border-radius: 12px;
  background: color-mix(in oklab, var(--brand-soft) 30%, transparent);
}
.login-perks li {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  font-size: .75rem;
  line-height: 1.45;
  font-weight: 500;
  color: var(--brand-strong);
}
.login-perks svg {
  width: .875rem;
  height: .875rem;
  flex: 0 0 auto;
  margin-top: .15rem;
  color: var(--success);
}

/* Two fields per line on anything but a phone. `minmax(0, 1fr)` rather than
   `1fr`: a grid item's default `min-width: auto` lets a long placeholder push
   the column wider than its share and break the row. */
.login-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 1.25rem;
}
@media (max-width: 30rem) {
  .login-row { grid-template-columns: minmax(0, 1fr); }
}

.login-optional {
  margin-left: .25rem;
  font-size: .625rem;
  font-weight: 500;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--muted-fg) 85%, transparent);
}

.login-switch {
  margin: 1.25rem 0 0;
  text-align: center;
  font-size: .8125rem;
  color: var(--muted-fg);
}
.login-switch a {
  margin-left: .25rem;
  font-weight: 600;
  color: var(--brand-strong);
  text-decoration: none;
  text-underline-offset: 4px;
}
.login-switch a:hover { color: var(--brand); text-decoration: underline; }

/* The expired page is an explanation, not an invitation -- so its mark drops
   the brand colour and its button drops the brand fill. */
.login-mark.is-muted {
  background: var(--surface);
  color: var(--muted-fg);
  box-shadow: none;
}

.login-submit.is-quiet {
  background: var(--surface);
  color: var(--foreground);
  box-shadow: inset 0 0 0 1px var(--border);
}
.login-submit.is-quiet:hover {
  background: var(--accent);
  box-shadow: inset 0 0 0 1px var(--brand-soft);
}

.login-meta {
  display: grid;
  gap: .75rem;
  margin: 1.25rem 0 0;
  padding: 1rem 1.125rem;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
}
.login-meta > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
.login-meta dt {
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted-fg);
}
.login-meta dd {
  margin: 0;
  font-size: .8125rem;
  font-weight: 500;
  color: var(--foreground);
  overflow-wrap: anywhere;
}

.login-dot.is-stopped { background: var(--destructive); }
/* Amber and slowly breathing: waiting is a state that resolves, and a static
   dot beside "pending review" reads as a process that has stalled. */
.login-dot.is-waiting {
  background: oklch(0.72 0.15 75);
  animation: login-dot-breathe 2.4s ease-in-out infinite;
}
@keyframes login-dot-breathe {
  0%, 100% { opacity: .45; }
  50%      { opacity: 1; }
}

/* --- motion ------------------------------------------------------------ */

@keyframes login-graph-drift {
  from { transform: translate(-50%, -50%) translate3d(-1.5%, -1%, 0) scale(1.01); }
  to   { transform: translate(-50%, -50%) translate3d(1.5%, 1%, 0) scale(1.04); }
}
@keyframes login-node-pulse {
  0%, 100% { opacity: .34; transform: scale(.92); }
  50%      { opacity: .78; transform: scale(1.12); }
}
@keyframes login-card-enter {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}
