/* Login. Deliberately a different world from the console: the app proper is
   a light, clinical instrument, and this is the brutalist poster the brand
   leads with. Tokens are lifted from the Anatomic Labs landing page so the
   two are the same design, not a lookalike. */

.auth {
  --a-bg: #0a0a0a;
  --a-surface: #161616;
  --a-primary: #ff3131;
  --a-text: #f5f3f1;
  --a-muted: #8ca0ac;
  --a-border: #2a2a2a;
  /* The hero's white frame. The unlocked bar borrows the same weight, so the
     two are set from one place. */
  --a-frame-border: 2px;
  --a-font: "Inter Tight", -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, sans-serif;
}

/* ------------------------------------------------------------------ login */
.auth {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  grid-template-columns: 1fr;
  /* `safe` so a short viewport scrolls from the top instead of clipping the
     poster off the top edge the way plain centring would. */
  align-content: safe center;
  justify-items: center;
  padding: clamp(24px, 5vh, 56px) 24px;
  background: var(--a-bg);
  color: var(--a-text);
  font-family: var(--a-font);
  overflow-y: auto;
}

/* Poster and form share one measure, so the form reads as the next line of
   the composition rather than as a second thing on the page. */
.auth__column { width: min(100%, 560px); }

.auth__poster { display: block; }
.auth__frame { width: 100%; }

/* The poster's exit once the bar has been slid. Delayed so the bar's pop is
   seen before the whole hero starts to go; the form arrives once it has. */
.auth__poster.is-leaving {
  animation: authFade 0.26s ease 0.32s both;
  pointer-events: none;
}
@keyframes authFade {
  to { opacity: 0; transform: translateY(-6px); }
}

.auth__panel {
  position: relative;
  width: 100%;
  aspect-ratio: 21 / 10;
  background: var(--a-primary);
  border: var(--a-frame-border) solid #fff;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  overflow: hidden;
}
.auth__panel-figure {
  width: auto;
  height: 82%;
  max-width: 82%;
  object-fit: contain;
  display: block;
}
.grain-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  background-repeat: repeat;
  pointer-events: none;
}

/* Brand on the left, location flush with the panel's right edge: the caption
   spans the frame, so space-between lines the location up with the hero. */
.auth__caption {
  margin-top: 12px;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
}
.auth__brand {
  margin: 0;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  line-height: 1;
  font-size: clamp(1.1rem, 1rem + 0.5vw, 1.5rem);
}
.auth__location {
  margin: 0;
  line-height: 1.2;
  font-size: 13px;
  font-weight: 500;
  text-align: right;
  white-space: nowrap;
}

/* ------------------------------------------------------------ unlock bar */
/* Same width as the hero so it reads as part of the poster, not a widget
   dropped beneath it. Square corners and the poster's border, per the brand. */
.unlock {
  position: relative;
  margin-top: 18px;
  height: 58px;
  /* border-box so the frame thickening on unlock doesn't grow the bar. */
  box-sizing: border-box;
  background: var(--a-surface);
  border: 1px solid var(--a-border);
  overflow: hidden;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
  transition: border-color 0.18s ease, border-width 0.18s ease;
}
.unlock__fill {
  position: absolute;
  top: 0; bottom: 0; left: 0;
  background: var(--a-primary);
  opacity: 0.22;
  pointer-events: none;
  transition: width 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
.unlock.is-dragging .unlock__fill { transition: none; }

.unlock__handle {
  position: absolute;
  top: 4px; bottom: 4px; left: 4px;
  width: 58px;
  /* border-box so the added border sits inside the 58px square instead of
     growing it. */
  box-sizing: border-box;
  display: grid;
  place-items: center;
  background: var(--a-primary);
  color: #fff;
  /* Same weight as unlock__arrow's strokeWidth, same color as the arrow
     itself (currentColor -> #fff here) — the handle's outline reads as an
     extension of the icon's own line rather than a separate decoration. */
  border: 2.4px solid #fff;
  cursor: grab;
  touch-action: none;
  will-change: transform;
  /* Springs back (or snaps to the end) when released; tracks the finger with
     no lag while it is actually being dragged. */
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
  /* A barely-there rightward nudge that repeats every few seconds — not a
     wave or a wobble, just a suggestion of the direction to drag. Idle for
     most of the cycle so it reads as an occasional hint, not motion that
     never stops. It's the handle itself that nudges — the same square that
     tracks the finger while dragging — not just the icon inside it. */
  animation: unlockHint 2.8s ease-in-out infinite;
}
.unlock.is-dragging .unlock__handle { cursor: grabbing; transition: none; }
/* The flight back to the start after letting go short of the end: a real
   overshoot-and-settle rather than the crisp ease the snap-to-end success
   case keeps, so a false start reads as the handle springing home, not
   snapping there. Only this one return gets it — .is-springing is added
   for exactly that flight and dropped the moment it is grabbed again. */
.unlock.is-springing .unlock__handle {
  transition: transform 0.65s cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* Stopped while actually being dragged or once unlocked, so the hint never
   competes with the finger or fights the inline transform driving position. */
.unlock.is-dragging .unlock__handle,
.unlock.is-unlocked .unlock__handle {
  animation: none;
}
.unlock__handle:focus-visible { outline: 2px solid #fff; outline-offset: -4px; }
@keyframes unlockHint {
  0%, 70%, 100% { transform: translateX(0); }
  80%           { transform: translateX(2px); }
  90%           { transform: translateX(0); }
}

.unlock__arrow,
.unlock__check {
  grid-area: 1 / 1;
  transition: opacity 0.18s ease, transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}
.unlock__check { opacity: 0; transform: scale(0.6); }

/* Reaching the end: the fill goes solid, the arrow flips to a check, the bar
   takes the hero's white frame, and the whole thing gives one short pop — the
   "click" of the lock opening. Solid red in a white frame is the poster's own
   panel in miniature, which is the point. */
.unlock.is-unlocked {
  border: var(--a-frame-border) solid #fff;
  animation: unlockPop 0.42s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.unlock.is-unlocked .unlock__fill { opacity: 1; width: 100% !important; }
/* The grain fades up with the pop. Only a `from` is given, so it settles on
   the opacity GrainOverlay sets inline — the hero's — rather than a copy of
   it kept here. Animating the overlay itself, not a wrapper: a wrapper at
   partial opacity would isolate the multiply blend and show raw grey noise. */
.unlock.is-unlocked .grain-overlay { animation: unlockGrainIn 0.3s ease both; }
@keyframes unlockGrainIn {
  from { opacity: 0; }
}
.unlock.is-unlocked .unlock__handle { background: #fff; color: var(--a-primary); }
.unlock.is-unlocked .unlock__arrow { opacity: 0; transform: translateX(6px); }
.unlock.is-unlocked .unlock__check { opacity: 1; transform: scale(1); }
@keyframes unlockPop {
  0%   { transform: scale(1);     box-shadow: 0 0 0 0 rgba(255, 49, 49, 0.55); }
  35%  { transform: scale(1.025); box-shadow: 0 0 0 10px rgba(255, 49, 49, 0); }
  100% { transform: scale(1);     box-shadow: 0 0 0 10px rgba(255, 49, 49, 0); }
}

/* The sign-in page proper. The poster has gone by the time this mounts, so
   the form is the only thing on the page: centred in the column, no panel and
   no hairline, and its entrance is the page turning over. */
.auth__form-side {
  display: flex;
  justify-content: center;
  animation: authRise 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes authRise {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: translateY(0); }
}
.auth__form {
  width: min(100%, 400px);
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.auth__form-head { display: flex; flex-direction: column; gap: 6px; }
.auth__title {
  margin: 0;
  font-size: clamp(1.5rem, 1.2rem + 1vw, 2rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.05;
}
.auth__sub { margin: 0; font-size: 13.5px; color: var(--a-muted); line-height: 1.5; }

.auth__field { display: flex; flex-direction: column; gap: 7px; }
.auth__label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--a-muted);
}
.auth__input {
  appearance: none;
  width: 100%;
  padding: 12px 14px;
  background: var(--a-surface);
  border: 1px solid var(--a-border);
  border-radius: 0;
  color: var(--a-text);
  font: 400 15px var(--a-font);
  transition: border-color 0.15s ease;
}
.auth__input:focus { outline: none; border-color: var(--a-primary); }
.auth__input::placeholder { color: #5a5a5a; }

.auth__submit {
  appearance: none;
  border: 0;
  padding: 13px 18px;
  background: var(--a-primary);
  color: #fff;
  font: 600 14px var(--a-font);
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: filter 0.15s ease, opacity 0.15s ease;
}
.auth__submit:hover { filter: brightness(1.08); }
.auth__submit:disabled { opacity: 0.5; cursor: default; }

.auth__error { margin: 0; font-size: 13px; color: #ff7d6b; line-height: 1.45; }
.auth__notice { margin: 0; font-size: 13px; color: var(--a-muted); line-height: 1.45; }
.auth__switch { margin: 0; font-size: 13px; color: var(--a-muted); }
.auth__link {
  appearance: none;
  border: 0;
  background: none;
  padding: 0;
  color: var(--a-text);
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}

@media (max-width: 860px) {
  .auth { padding: 24px 20px 32px; --a-frame-border: 1.5px; }
  .auth__panel { aspect-ratio: 4 / 3; }
}

@media (prefers-reduced-motion: reduce) {
  .unlock.is-unlocked, .unlock.is-unlocked .grain-overlay, .auth__form-side, .auth__poster.is-leaving { animation: none; }
  .auth__poster.is-leaving { opacity: 0; }
  .unlock__handle, .unlock__fill { transition: none; }
  .unlock__handle { animation: none; }
  /* Higher specificity than the blanket rule above, so it needs its own
     override to actually lose the bouncy return under reduced motion. */
  .unlock.is-springing .unlock__handle { transition: none; }
}
