/*
 * password-gate.css — Password-protected project gate.
 *
 * Only ever linked (see scripts/build.js buildRoutedPages) from the built
 * page of a project with `protected: true` — never shipped to any other
 * page. Everything here scopes off body.is-password-protected so it can't
 * accidentally leak onto a normal project page even if the link were ever
 * present by mistake.
 *
 * The gate is visible by DEFAULT (no JS required to look correct — see
 * password-gate.js's header comment); JS only adds .is-unlocked once the
 * password is correct, which is what this file uses to reveal the real
 * page and hide the gate again.
 */

/* ---------- Locked state: hide the real page, show the gate ---------- */

/* .project-page (project.css) paints body white — this repaints it blue
 * while locked. Needs 3 classes' worth of specificity to beat that 1-class
 * rule regardless of stylesheet order. The <html> element's own inline
 * background (set at build time, see projectBgColor in build.js) is
 * already blue from the very first paint; this is what keeps it blue once
 * body's own background takes over. */
.project-page.is-password-protected:not(.is-unlocked) {
  background-color: var(--color-accent);
  color: var(--color-fg-dark);
}

.is-password-protected:not(.is-unlocked) .project-shell,
.is-password-protected:not(.is-unlocked) .static-get-in-touch,
.is-password-protected:not(.is-unlocked) .static-info-row {
  display: none;
}

/* The logo and back arrow stay visible and on-brand for the gate itself —
 * same position/size/behavior as any other project page, just recolored
 * white for the blue background. Back arrow's own "close fullscreen or go
 * home" logic (fullscreen.js) is irrelevant here (no fullscreen state can
 * exist while locked, since the gallery is never built), so it always just
 * goes home, unchanged. The mobile-only .site-header{display:none} rule in
 * project.css is deliberately overridden — the logo stays visible on
 * mobile for the gate, at its normal home-page size/position. */
.is-password-protected:not(.is-unlocked) .site-header {
  display: flex;
}

/* The scroll chrome-masks (project.css .project-page::before/::after) have
 * nothing to mask here — no gallery/description exists yet — and being
 * white, they'd sit right on top of the (also white) logo. Same pattern
 * fullscreen.css already uses for .fullscreen-active. */
.is-password-protected:not(.is-unlocked)::before,
.is-password-protected:not(.is-unlocked)::after {
  display: none;
}

.is-password-protected:not(.is-unlocked) .site-logo {
  background-color: var(--color-fg-dark);
}

.is-password-protected:not(.is-unlocked) .static-back-arrow {
  color: var(--color-fg-dark);
}

/* The custom cursor (cursor.js) reads --cursor-color, which project.css
 * points at --project-highlight — normally on-brand, but on the gate that
 * resolves to the same blue as the background, making the cursor
 * invisible. White while locked, same as everything else here. */
.is-password-protected:not(.is-unlocked) {
  --cursor-color: var(--color-fg-dark);
}

/* ---------- Unlocked state: hide the gate ---------- */

.is-password-protected.is-unlocked .password-gate {
  display: none;
}

/* ---------- Gate layout ---------- */

.password-gate {
  position: fixed;
  inset: 0;
  z-index: var(--z-content);
  display: flex;
  align-items: center;
  justify-content: center;
  /* --safe-pad-top/--safe-pad-bottom (project.css) keep a notch/home-
   * indicator safe area (viewport-fit=cover, see project.html) from
   * crowding the row, without adding any padding on devices that
   * report 0. */
  padding: var(--safe-pad-top) var(--page-pad-x) var(--safe-pad-bottom);
  /* Belt and suspenders: body/html already paint the full viewport blue
   * (see the rule above and projectBgColor in build.js), but this fixed,
   * inset:0 element gets its own background too so the gate is guaranteed
   * to cover the true viewport regardless of any body-height edge case
   * (e.g. a mobile browser's own collapsing toolbar). */
  background-color: var(--color-accent);
  color: var(--color-fg-dark);
}

/* One centered column — hangman above fields, "Password protected" pinned
 * to the bottom edge on its own (see .password-gate-status) rather than
 * sitting in this row. Same structure at every viewport width; only the
 * hangman/field sizing differs by breakpoint below. */
.password-gate-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 56px;
  width: 100%;
}

/* ---------- Password fields ---------- */

.password-gate-fields {
  position: relative;
  order: 2;
  display: flex;
  gap: 0.3em;
  font-size: clamp(28px, 4.5vw, 48px);
  font-weight: var(--fw-light);
  letter-spacing: 0.02em;
  cursor: text;
}

/* Blank state is an empty slot (see build.js buildPasswordGateBlock) with
 * the blank line drawn here via border-bottom, not a literal "_" glyph —
 * gives an exact, thin line weight independent of how heavy the font's
 * own underscore renders. A fixed `height` (not just padding under
 * whatever content happens to be there) keeps the line at the same
 * vertical position whether the slot is empty or holds a letter —
 * without it, an empty slot has no glyph to establish line-height, so
 * its box (and the border sitting at its bottom edge) is shorter than a
 * filled one, and the line visibly jumps down as each slot fills in. */
.password-field-slot {
  display: inline-block;
  width: 0.7em;
  height: 1em;
  line-height: 1;
  text-align: center;
  border-bottom: 1.5px solid currentColor;
  padding-bottom: 0.08em;
}

/* Once correct, the letter stands on its own — the blank line has
 * nothing left to indicate. */
.password-field-slot.is-filled {
  border-bottom-color: transparent;
}

/* Real input, present for keyboard/mobile-keyboard/a11y — visually
 * invisible, sized to cover the fields so tapping anywhere on them (the
 * label) focuses it. type="text" (not "password") deliberately: the
 * fields already echo typed characters in the clear, and "password"
 * inputs invite browser save-password / breach-warning prompts that
 * would be a confusing, unwanted interruption on what's a soft gate, not
 * a real login. font-size: 16px prevents iOS Safari's auto-zoom-on-focus. */
.password-gate-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  color: transparent;
  caret-color: transparent;
  font-size: 16px;
  opacity: 0;
}

/* ---------- Hangman illustration ---------- */

.password-gate-hangman {
  order: 1;
  width: clamp(90px, 12vw, 130px);
}

.hangman-illustration {
  display: block;
  width: 100%;
  height: auto;
  color: var(--color-fg-dark);
  overflow: visible;
}

/* Every stage but the gallows itself starts invisible — pure CSS, correct
 * before password-gate.js even loads. Each is solid fill art (Martí's
 * hand-drawn pieces, see assets/icons/hangman/), so the reveal is a
 * scale + fade "pop" (transform-origin at each piece's own attachment
 * point) rather than a stroke trace-on — a filled shape has no path
 * length to draw along. The overshoot easing gives it a little of the
 * same "drip landing" character as the artwork itself. password-gate.js
 * adds .is-revealed per miss.
 *
 * --hx/--hy (set inline per stage by build.js, in the sprite's own
 * viewBox units) place each piece within the composed figure. They live
 * in the same `transform` as the scale rather than on a separate
 * wrapper element: a CSS `transform` on an SVG element overrides its own
 * `transform` attribute rather than composing with it, so positioning
 * and this reveal animation can't be split across an SVG attribute and a
 * CSS property on the same element — they have to be one CSS transform,
 * which is what this is. */
.hangman-stage:not([data-stage="structure"]) {
  opacity: 0;
  transform: translate(var(--hx, 0), var(--hy, 0)) scale(0.35);
  transform-box: fill-box;
  transform-origin: 50% 0%;
  transition: opacity 220ms ease, transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.hangman-stage.is-revealed {
  opacity: 1;
  transform: translate(var(--hx, 0), var(--hy, 0)) scale(1);
}

/* ---------- Status text ---------- */

/* Pinned to the bottom edge on its own, centered — same treatment as the
 * project page's LOCATION/YEAR/DESCRIPTION labels (project.css's
 * .info-links-cell/.info-next-cell dt), not a bespoke size for the gate. */
.password-gate-status {
  position: fixed;
  left: var(--page-pad-x);
  right: var(--page-pad-x);
  bottom: var(--safe-pad-bottom);
  margin: 0;
  text-align: center;
  font-size: var(--fs-label);
  font-weight: var(--fw-light);
  letter-spacing: var(--ls-label);
  opacity: 0.7;
  white-space: normal;
}

/* ---------- Mobile ---------- */

/* Structure is shared with desktop (see .password-gate-row above) — only
 * the hangman/field sizing shrinks for a narrow viewport, and the pair
 * sits a bit above dead-center rather than exactly on it. The upward
 * nudge is a transform on the hangman/fields themselves, not on
 * .password-gate-row — .password-gate-status is a `position: fixed`
 * child of that row, and a `transform` on an ancestor becomes the
 * containing block for a fixed descendant, which would drag the status
 * line up out of its bottom-pinned position along with everything else. */
@media (max-width: 600px) {
  .password-gate-hangman {
    width: clamp(90px, 24vw, 140px);
    transform: translateY(-20px);
  }

  .password-gate-fields {
    font-size: clamp(26px, 8vw, 38px);
    transform: translateY(-20px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hangman-stage {
    transition: none;
  }
}
