/* -----------------------------------------------------------------------------
 * Project:       Kirby Castle
 * Owner:         Joshua H. Kirby
 * Copyright:     Copyright (c) 2026 Joshua H. Kirby. All rights reserved.
 * Last Modified: 2026-07-10
 * --------------------------------------------------------------------------- */

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-height: 100vh;
  font-family: "Cinzel", serif;
  color: var(--gold-light);
  overflow: hidden;
}

/* ── PAGE BACKGROUND ─────────────────────────────────────── */
/* .castle-page (the drifting shadow band + castle art + vignette) and the
 * .star-field/.star* twinkling stars moved to css/castle_background.css --
 * shared with register.html, which uses the exact same background. Loaded
 * before this file (see outside.html's <head>). Only what's specific to
 * this page's own decorative layers (the banner shimmer) stays below. */

/* Ambient motion above is decorative only — respect reduced-motion. Split
 * from castle_background.css's own reduced-motion block (.castle-page::
 * before/::after, .star) since .banner-shimmer is this page's own. */
@media (prefers-reduced-motion: reduce) {
  .banner-shimmer::before {
    animation: none;
  }
}

/* ── TOP BANNER ──────────────────────────────────────────── */

.full-banner {
  position: absolute;
  top: 1rem;
  left: 2rem;
  right: 2rem;
  z-index: 3;
  height: 8.6rem;
  overflow: visible;
}

/*
 * The bar body is a uniform vertical slice of the plate art, stretched
 * horizontally. Because the slice is a constant cross-section (black fill with
 * gold rails top & bottom), stretching it sideways causes no visible
 * distortion, and the gold rails run the full length of the bar.
 * background-size height is 100%, so the rails land at the same vertical
 * position as the natural-aspect end caps below — the seams are invisible.
 */
.bar-mid {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 6.5rem;
  right: 6.5rem;
  z-index: 1;
  background-image: url("../../images/banner_side.png");
  background-repeat: no-repeat;
  background-size: 430% 100%;
  background-position: 56% center;
}

/*
 * End caps: the same art at natural aspect ratio, so the tail + diamond are
 * never squashed or cropped. Their straight inner section overlaps .bar-mid.
 */
.banner-cap {
  position: absolute;
  top: 0;
  height: 100%;
  width: auto;
  z-index: 2;
  display: block;
}

.cap-left {
  left: 0;
}

.cap-right {
  right: 0;
  transform: scaleX(-1);
}

/* Center K-crest hangs down over the seam of the two plates */
.banner-crest {
  position: absolute;
  left: 50%;
  top: -0.7rem;
  transform: translateX(-50%);
  height: 8.6rem;
  z-index: 4;
  pointer-events: none;
}

.banner-crest img {
  height: 100%;
  width: auto;
  display: block;
  filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.55));
}

/*
 * Periodic gold/white shine swept across the crest, top-right to
 * bottom-left, every 10s. Masked with the same logo art so the sweep is
 * clipped to the shield's silhouette rather than its rectangular box.
 */
.banner-shimmer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  mix-blend-mode: screen;
  -webkit-mask-image: url("../../images/logo.png");
  mask-image: url("../../images/logo.png");
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.banner-shimmer::before {
  content: "";
  position: absolute;
  inset: -50% -20%;
  background: linear-gradient(
    135deg,
    transparent 40%,
    rgba(255, 255, 255, 0.5) 47%,
    var(--gold-light) 50%,
    rgba(255, 255, 255, 0.5) 53%,
    transparent 60%
  );
  background-repeat: no-repeat;
  background-size: 260% 260%;
  animation: banner-shimmer-sweep 10s ease-in-out infinite;
}

/*
 * The 0%/16% pair is the visible sweep (top-right corner to bottom-left);
 * 16%-100% holds the stripe off-canvas (bottom-left) for the rest of the
 * 10s cycle, so the loop restart snaps between two off-screen positions
 * rather than popping mid-view.
 */
@keyframes banner-shimmer-sweep {
  0% {
    background-position: -60% 160%;
  }

  16% {
    background-position: 160% -60%;
  }

  100% {
    background-position: 160% -60%;
  }
}

.banner-title {
  position: absolute;
  left: 18%;
  top: 50%;
  transform: translateY(calc(-50% - 2px));
  z-index: 3;
  margin: 0;
  font-size: var(--banner-text-size);
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--gold-light);
  text-shadow: var(--text-shadow);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 32%;
}

.knock-button {
  position: absolute;
  right: 18%;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.4rem 0.8rem;
  border: 0;
  background: transparent;
  color: var(--gold-light);
  font-family: "Cinzel", serif;
  font-size: var(--banner-text-size);
  cursor: pointer;
  text-shadow: var(--text-shadow);
  transition: transform 120ms ease, color 160ms ease;
}

.knock-button span {
  transform: translateY(-2px);
}

.knock-button:hover {
  color: #ffe6a3;
}

.knock-button:active {
  transform: translateY(-50%) scale(0.96);
}

.knock-button:active .door-knocker {
  filter: drop-shadow(0 0 4px color-mix(in srgb, var(--gold) 40%, transparent));
}

.door-knocker {
  height: 2.6rem;
  width: auto;
  object-fit: contain;
  flex-shrink: 0;
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--gold) 30%, transparent));
  transition: filter 150ms ease;
}

.knock-button:hover .door-knocker {
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--gold) 60%, transparent));
}

/* ── LOGIN PANEL ──────────────────────────────────────────── */

.login-panel {
  position: relative;
  z-index: 3;
  align-self: flex-start;
  margin-top: clamp(7.6rem, 9vh, 8.4rem);

  width: min(580px, 90vw);
  padding: clamp(1.2rem, 3vh, 2rem) 3.2rem;

  background: linear-gradient(
    to bottom,
    rgba(10, 15, 18, 0.82),
    rgba(5, 8, 11, 0.78)
  );

  border: 2px solid var(--gold);
  border-radius: 26px;
  overflow: hidden;

  box-shadow:
    0 25px 65px rgba(0, 0, 0, 0.55),
    inset 0 0 35px rgba(255, 215, 120, 0.06);

  /*
   * No backdrop-filter here on purpose: combined with the ::before blur
   * layer, resizing/repositioning this panel triggers a Chromium GPU
   * compositing bug that leaves stale rectangular paint artifacts
   * elsewhere on the page (unrelated bands of wrong pixels). The gradient
   * background alone is opaque enough that the blur-through wasn't
   * buying much visually.
   */
  transition:
    opacity 260ms ease,
    transform 260ms ease;

  --mx: 50%;
  --my: 50%;
}

.login-panel.hidden {
  opacity: 0;
  transform: translateY(18px) scale(0.98);
  pointer-events: none;
}

/*
 * Cursor-tracking torchlight: a soft radial highlight positioned via
 * --mx/--my (set from JS on mousemove). z-index:0 keeps it behind
 * .login-form, which is given z-index:1 below — without that, this
 * absolutely-positioned, non-negative-z-index layer would paint above
 * the in-flow form content per normal stacking order.
 */
.login-panel::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: radial-gradient(
    circle 260px at var(--mx) var(--my),
    rgba(255, 215, 120, 0.16),
    transparent 70%
  );
  opacity: 0;
  transition: opacity 300ms ease;
  pointer-events: none;
}

.login-panel.glow-active::before {
  opacity: 1;
}

/* ── LOGIN FORM ──────────────────────────────────────────── */

.login-form {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: clamp(0.9rem, 2.2vh, 1.6rem);
}

.login-error {
  margin: 0 0 -0.3rem;
  padding: 0.6rem 0.9rem;
  background: rgba(120, 20, 20, 0.35);
  border: 1.5px solid #c0564f;
  border-radius: 10px;
  color: #f3b8b0;
  font-size: 0.85rem;
  text-align: center;
}

.login-error p {
  margin: 0;
}

.login-error p + p {
  margin-top: 0.3rem;
}

.input-shell {
  height: clamp(2.8rem, 6vh, 3.5rem);
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 0 1rem;
  background: rgba(7, 11, 14, 0.48);
  border: 1.5px solid var(--gold);
  border-radius: 14px;
  cursor: text;
  box-shadow:
    inset 0 0 18px rgba(255, 215, 120, 0.03),
    0 8px 18px rgba(0, 0, 0, 0.22);
  transition:
    border-color 220ms cubic-bezier(0.34, 1.56, 0.64, 1),
    box-shadow 220ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.input-shell:hover {
  border-color: #e8c672;
}

.input-shell:focus-within {
  border-color: #fbf3d9;
  box-shadow:
    inset 0 0 18px rgba(255, 215, 120, 0.03),
    0 8px 18px rgba(0, 0, 0, 0.22),
    0 0 10px rgba(251, 243, 217, 0.35);
}

/* Only the password row ever carries .form-field alongside .input-shell on
 * the same <label> (see outside.html) -- set by outside.js's Reset
 * Password flow via the shared setFieldState (name_field.js), which
 * toggles is-valid/is-invalid on input.closest('.form-field') -- here
 * that's this very element, not a separate wrapper, so these classes land
 * directly on .input-shell itself. Same green/red convention as every
 * other .form-field in the app, just reusing this page's own gold box
 * instead of form_field.css's. */
.input-shell.is-valid {
  border-color: var(--valid);
}

.input-shell.is-invalid {
  border-color: var(--invalid);
}

/*
 * Fixed-width slot so email_logo.png (wider) and lock_logo.png (narrower)
 * take up the same horizontal space — otherwise the input text after each
 * icon starts at a different x position.
 */
.icon-slot {
  width: 1.8rem;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.input-icon {
  height: 1.18rem;
  width: auto;
  object-fit: contain;
  opacity: 0.9;
  transition: opacity 160ms ease, filter 160ms ease,
    transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.input-icon:hover {
  transform: scale(1.15);
}

.input-shell:focus-within .input-icon {
  opacity: 1;
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--gold) 60%, transparent));
}

/*
 * lock_logo.png's glyph is narrower/taller than email_logo.png's, so it
 * needs a taller box to read as the same visual size next to it.
 */
.icon-lock {
  height: 1.7rem;
}

.input-shell input {
  width: 100%;
  border: 0;
  outline: 0;
  background: transparent;
  font-family: "Cinzel", serif;
  font-size: 0.95rem;
  color: var(--gold-light);
  caret-color: var(--gold-light);
}

.input-shell input::placeholder {
  color: color-mix(in srgb, var(--gold-light) 72%, transparent);
}

/* Password visibility toggle (.password-toggle/.eye-icon/.eye-slash) moved
 * to css/password_toggle.css -- shared with register.html, which uses the
 * exact same eye-icon mechanism (see password_toggle.js's
 * initPasswordToggle()). It sits after the input, inside the same flex row
 * as icon-slot/input, so .input-shell's own `padding: 0 1rem` and
 * `gap: 0.8rem` already give it breathing room from both the input text and
 * the box's right border with no extra rules needed here. */

/* "Reset" link (outside.js's Reset Password flow) -- sits between the
 * input and the eye-icon toggle, in that same flex row, so the shell's own
 * gap already spaces it from both neighbors. Plain text, no background/
 * border, muted gold at rest -- glows brighter gold on hover/focus, same
 * "gold glow" language as .confirm-popup-crest:hover elsewhere in the app.
 * Relabeled to "Login" by outside.js while the flow is active; the class
 * name stays .reset-link regardless of which word is currently showing.
 * Hidden (opacity, not display -- so it never shifts layout appearing/
 * disappearing) unless the password row itself is hovered or has focus
 * within it; pointer-events: none while hidden so it can't be clicked (or
 * accidentally eat a hover) when it's not actually visible. The 'R'/'L'
 * keyboard shortcuts (outside.js) work regardless of this -- they're not
 * gated on the link's own visibility at all, only on the login panel
 * being open. */
.reset-link {
  flex-shrink: 0;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;

  font-family: "Cinzel", serif;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: color-mix(in srgb, var(--gold-light) 65%, transparent);

  opacity: 0;
  pointer-events: none;
  transition: color 160ms ease, text-shadow 160ms ease, opacity 160ms ease;
}

.input-shell:hover .reset-link,
.input-shell:focus-within .reset-link {
  opacity: 1;
  pointer-events: auto;
}

.reset-link:hover,
.reset-link:focus-visible {
  color: #fbf3d9;
  text-shadow: 0 0 8px color-mix(in srgb, var(--gold) 70%, transparent);
  outline: none;
}

/* One combined status line for the whole Reset Password flow -- the NEW
 * state's character-count hint, mismatch/wrong-code errors, the "Emailing
 * code…" shimmer, and the "Time Remaining: Ns" countdown all share this
 * single line (see outside.js). Plain gold text by default (the hint/
 * countdown/shimmer cases); .is-error switches to the exact same red
 * boxed look as .login-error above (not just red text) for an actual
 * error message, so the two read as one consistent "something's wrong"
 * treatment on this page rather than two different styles. */
.password-reset-status {
  margin: -0.6rem 0 0;
  padding: 0 0.2rem;

  font-size: 0.78rem;
  text-align: center;
  color: color-mix(in srgb, var(--gold-light) 80%, transparent);
}

.password-reset-status.is-error {
  margin: 0 0 -0.3rem;
  padding: 0.6rem 0.9rem;
  background: rgba(120, 20, 20, 0.35);
  border: 1.5px solid #c0564f;
  border-radius: 10px;
  color: #f3b8b0;
  font-size: 0.85rem;
}

/* ── ENTER BUTTON ──────────────────────────────────────────── */

.enter-button {
  display: block;
  margin: 0.4rem auto 0;
  width: min(200px, 100%);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}

.enter-button img {
  width: 100%;
  height: auto;
  display: block;
  transition: filter 160ms ease, transform 160ms ease;
}

.enter-button:hover img {
  filter: brightness(1.15) drop-shadow(0 0 10px color-mix(in srgb, var(--gold) 45%, transparent));
  transform: scale(1.02);
}

.enter-button:active img {
  filter: brightness(1.05) drop-shadow(0 0 6px color-mix(in srgb, var(--gold) 35%, transparent));
  transform: scale(0.97);
}

/* ── LOWER FLOURISH ──────────────────────────────────────── */

.lower-flourish {
  display: flex;
  justify-content: center;
}

.lower-flourish img {
  width: min(200px, 55%);
  height: 1.6rem;
  opacity: 0.82;
}

/* ── RESPONSIVE ──────────────────────────────────────────── */

@media (max-width: 760px) {
  .castle-page {
    padding: 1rem;
  }

  .full-banner {
    left: 1rem;
    right: 1rem;
    height: 6.6rem;
  }

  .bar-mid {
    left: 4.6rem;
    right: 4.6rem;
  }

  .banner-crest {
    height: 6.4rem;
    top: 0.2rem;
  }

  .banner-title {
    font-size: 1rem;
    left: 15%;
    max-width: 30%;
  }

  .knock-button {
    font-size: 1rem;
    padding: 0.3rem 0.5rem;
    right: 10%;
  }

  .door-knocker {
    height: 2rem;
  }

  .login-panel {
    margin-top: 7.6rem;
    padding: 1.6rem 1.4rem 1.6rem;
    width: 95vw;
  }

  .input-shell {
    height: 3.1rem;
    gap: 0.6rem;
    padding: 0 0.7rem;
  }

  .input-icon {
    height: 1rem;
  }

  .icon-lock {
    height: 1.44rem;
  }

  .input-shell input {
    font-size: 0.8rem;
  }

  .enter-button {
    width: 50%;
  }
}
