/* Homepage: pure black, the swinging figure, and the login section. Nothing else. */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  background: #000;
  color: #bdbdbd;
  font: 400 13px/1.6 'IBM Plex Mono', ui-monospace, Consolas, monospace;
  letter-spacing: .02em;
  -webkit-font-smoothing: antialiased;
  display: grid; place-items: center start;          /* login sits on the left */
  padding-left: clamp(28px, 12vw, 240px);
  min-height: 100vh; min-height: 100dvh;
  overflow: hidden;
  animation: fade 1.6s ease both;
}
body.leaving { animation: fade-out .6s ease forwards; }
@keyframes fade { from { opacity: 0; } }
@keyframes fade-out { to { opacity: 0; } }
button, input { font: inherit; color: inherit; letter-spacing: inherit; }
:focus-visible { outline: 1px dashed #555; outline-offset: 3px; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ═════════════ the figure ═════════════
   Source image: /assets/hanging.png, 233 × 1024. The rope in it is centred at x = 100
   and is extended to the ceiling with /assets/rope.png (a slice of the same rope).
   Tune here: */
:root {
  --swing-angle: 1.3deg;                     /* max tilt each way, around the ceiling anchor */
  --swing-half: 3.8s;                        /* one sweep (left → right); full cycle = 2× */
  --fig-h: clamp(260px, 56vh, 600px);        /* displayed height; width follows the aspect ratio */
  --fig-right: clamp(40px, 11vw, 240px);     /* breathing room from the right edge */
  --tone: grayscale(1) brightness(.72) contrast(1.06);
  --fig-w: calc(var(--fig-h) * 233 / 1024);
  --fig-top: calc((100vh - var(--fig-h)) / 2); /* vertically centred */
}
/* on 2× screens, cap the size so the 1024 px source is never upscaled */
@media (min-resolution: 2dppx) { :root { --fig-h: clamp(260px, 56vh, 512px); } }

.defs { position: absolute; width: 0; height: 0; overflow: hidden; }

.sayori {
  position: fixed; z-index: 0; top: 0; right: var(--fig-right);
  width: var(--fig-w); height: calc(var(--fig-top) + var(--fig-h));
  pointer-events: none; user-select: none;
  transform-origin: calc(100% * 100 / 233) 0;   /* the rope's anchor point at the ceiling */
  animation: swing var(--swing-half) cubic-bezier(.37, 0, .63, 1) infinite alternate;  /* sine-like easing, slows at each end */
  will-change: transform;
}
@keyframes swing {
  from { transform: rotate(calc(var(--swing-angle) * -1)); }
  to   { transform: rotate(var(--swing-angle)); }
}

.rope {
  position: absolute; top: 0;
  left: calc(var(--fig-w) * 94 / 233); width: calc(var(--fig-w) * 12 / 233);
  height: calc(var(--fig-top) + var(--fig-h) * 8 / 1024);   /* overlaps the image's own rope by a few px */
  background: url(/assets/rope.png) repeat-y 0 100% / 100% auto;
  filter: var(--tone);
}

.fig {
  position: absolute; left: 0; top: var(--fig-top);
  width: var(--fig-w); height: var(--fig-h);
  isolation: isolate;
}
.fig > * { position: absolute; inset: 0; width: 100%; height: 100%; }

/* The figure is drawn as two channel layers (red + green/blue) screened together, which
   adds up to the normal grayscale image. Offsetting them during a glitch = RGB split. */
.ch-r  { filter: var(--tone) url(#only-r); }
.ch-gb { filter: var(--tone) url(#only-gb); mix-blend-mode: screen; }

/* glitch-only layers: hidden until a glitch event */
.ghost, .tear { opacity: 0; filter: var(--tone); }
.tear { background: #000; }   /* covers the original band, so the slice looks displaced */
.lines {
  opacity: .04;
  background: repeating-linear-gradient(to bottom, rgba(0,0,0,.7) 0 1px, transparent 1px 3px);
  -webkit-mask: url(/assets/hanging.png) 0 0 / 100% 100% no-repeat;
          mask: url(/assets/hanging.png) 0 0 / 100% 100% no-repeat;
}

/* ── glitch events (triggered at random intervals by auth.js; each part can fire alone or together) ── */
.fig[data-rgb] .ch-r  { animation: split-r .42s steps(1) both; }
.fig[data-rgb] .ch-gb { animation: split-gb .42s steps(1) both; }
@keyframes split-r  { 0% { transform: translateX(-3px); } 30% { transform: translateX(2px); } 55% { transform: translate(-5px, 1px); } 80% { transform: translateX(-1px); } 100% { transform: none; } }
@keyframes split-gb { 0% { transform: translateX(3px); } 30% { transform: translateX(-2px); } 55% { transform: translate(4px, -1px); } 80% { transform: translateX(1px); } 100% { transform: none; } }

.fig[data-tear] .tear-1 {
  clip-path: inset(var(--t1) 0 calc(100% - var(--t1) - var(--h1)) 0);
  animation: tear-1 .36s steps(1) both;
}
.fig[data-tear] .tear-2 {
  clip-path: inset(var(--t2) 0 calc(100% - var(--t2) - var(--h2)) 0);
  animation: tear-2 .3s steps(1) .06s both;
}
@keyframes tear-1 { 0% { opacity: 1; transform: translateX(var(--x1)); } 35% { transform: translateX(calc(var(--x1) * -.6)); } 60% { transform: translateX(calc(var(--x1) * 1.4)); } 85% { opacity: 1; transform: translateX(calc(var(--x1) * .3)); } 100% { opacity: 0; transform: none; } }
@keyframes tear-2 { 0% { opacity: 1; transform: translateX(var(--x2)); } 50% { transform: translateX(calc(var(--x2) * -1)); } 90% { opacity: 1; } 100% { opacity: 0; transform: none; } }

.fig[data-tear] .lines, .fig[data-rgb] .lines { animation: lines .45s steps(2) both; }
@keyframes lines { 0% { opacity: .55; transform: translateX(2px); } 50% { opacity: .35; transform: translateX(-3px); } 100% { opacity: .04; transform: none; } }

.fig[data-ghost] .ghost { animation: ghost .9s ease-out both; }
@keyframes ghost { 0% { opacity: .38; transform: translateX(var(--gx)); } 18% { opacity: .2; transform: translateX(calc(var(--gx) * 1.6)); } 100% { opacity: 0; transform: translateX(calc(var(--gx) * 2.2)); } }

.fig[data-flicker] { animation: flicker .5s steps(1) both; }
@keyframes flicker { 0% { opacity: .55; } 12% { opacity: 1; } 30% { opacity: .3; filter: brightness(1.5); } 42% { opacity: 1; filter: none; } 70% { opacity: .8; } 100% { opacity: 1; } }

/* ── login section ── */
.login { position: relative; z-index: 2; width: min(300px, calc(100vw - 48px)); display: grid; }
.panel {
  grid-area: 1 / 1; display: flex; flex-direction: column; gap: 14px;
  opacity: 0; visibility: hidden; transform: translateY(4px);
  transition: opacity .5s ease, transform .5s ease, visibility 0s .5s;
}
.panel.active { opacity: 1; visibility: visible; transform: none; transition: opacity .6s ease .1s, transform .6s ease .1s; }

.input {
  width: 100%; background: transparent; border: 0; border-bottom: 1px solid #1e1e1e; border-radius: 0;
  padding: 8px 2px; outline: none; transition: border-color .4s;
}
.input:focus { border-color: #555; }
.input::placeholder { color: #444; }

.row { display: flex; justify-content: space-between; align-items: center; font-size: 11.5px; color: #555; }
.check { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; }
.check input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.check .box { width: 11px; height: 11px; border: 1px solid #333; display: inline-grid; place-items: center; }
.check input:checked + .box::after { content: ''; width: 5px; height: 5px; background: #8a1c1c; }
.check input:focus-visible + .box { outline: 1px dashed #555; outline-offset: 2px; }

.link { background: none; border: 0; padding: 0; cursor: pointer; color: #555; font-size: 11.5px; transition: color .3s; }
.link:hover { color: #bdbdbd; }
.link.center { align-self: center; }

.btn {
  margin-top: 6px; padding: 10px; background: transparent; border: 1px solid #222; cursor: pointer;
  letter-spacing: .14em; transition: border-color .4s, color .4s;
}
.btn:hover { border-color: #555; color: #e0e0e0; }
.btn[disabled] { opacity: .4; cursor: wait; }

.msg { min-height: 1.4em; margin: 0; font-size: 11.5px; text-align: center; color: #666; }
.msg.err { color: #9a3a3a; }

.note { margin: 0; font-size: 11.5px; color: #777; text-align: center; }
.key {
  display: block; padding: 12px; text-align: center; border: 1px solid #222;
  font-size: 14px; letter-spacing: .12em; color: #d6d6d6; user-select: all; word-break: break-all;
}

/* phones: no room side by side — she hangs top-right, the login section sits below her */
@media (max-width: 640px) {
  body { place-items: end center; padding: 0 0 max(6vh, 28px); }
  :root { --fig-h: min(40vh, 340px); --fig-right: 14vw; --fig-top: 4vh; }
}

@media (prefers-reduced-motion: reduce) {
  body, .panel { animation: none; transition: none; }
  .sayori, .fig, .fig > * { animation: none !important; }
}
