/* ──────────────────────────────────────────────────────────
   Computer Angel — a field, not an object
────────────────────────────────────────────────────────── */

:root {
  --black: #08080A;
  --sans:  'Jost', 'Century Gothic', sans-serif;
  --mono:  'IBM Plex Mono', 'Courier New', monospace;
  --gold:  rgba(240, 210, 170, 0.6);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* the archive/field-notes/index are real content, not locked behind
   the captcha — only the hero statement itself is the "you're not
   in yet" gate. scrolling exists from the first paint.
   html (not body) owns the scroll — a fixed height on both here was
   turning body into its own tiny scroll container instead of letting
   the actual page/window scroll, which is what scrollIntoView() and
   the wheel both expect. */
html {
  background: var(--black);
  height: 100%; overflow-y: auto; overflow-x: hidden;
}
body {
  background: var(--black);
  min-height: 100%;
}

#field {
  position: fixed; inset: 0; width: 100%; height: 100%;
  display: block; z-index: 0;
  transition: filter 1.1s ease;
}
/* blurred until you've actually entered — you're not on the page yet */
body.gate #field { filter: blur(16px) saturate(0.85); }

/* every overlay text/icon element gets this — without it, light
   type disappears into the bright fog/sky parts of the photo,
   same problem the field glyphs had */
.motto, .social a svg {
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.75)) drop-shadow(0 0 6px rgba(0,0,0,0.5));
}

/* the hero statement stays hidden until the captcha resolves — only
   the archive/field-notes below it are visible right away, scrollable
   underneath the (fixed, centred) captcha */
.hero {
  transition: opacity 1s ease 0.15s;
}
body.gate .hero {
  opacity: 0; pointer-events: none;
}

/* the landing page's centre — motto with the socials gathered
   right beneath it. first full-height screen of a scrollable page
   now, not pinned in place, so the archive can live underneath it */
.hero {
  position: relative; min-height: 100svh; z-index: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 26px; pointer-events: none;
}

/* a quiet cue that there's more below — only once you've entered */
.scroll-cue {
  position: absolute; left: 50%; bottom: 6%; transform: translateX(-50%);
  width: 14px; height: 22px; border: 1px solid rgba(248,244,235,0.5);
  border-radius: 8px; opacity: 0.6;
}
.scroll-cue::after {
  content: ''; position: absolute; left: 50%; top: 5px; width: 3px; height: 6px;
  margin-left: -1.5px; border-radius: 2px; background: rgba(248,244,235,0.7);
  animation: scroll-cue-drift 1.8s ease-in-out infinite;
}
@keyframes scroll-cue-drift { 0%,100% { opacity: .8; transform: translateY(0); } 50% { opacity: .2; transform: translateY(6px); } }

.motto {
  font-family: var(--sans); font-weight: 300;
  font-size: clamp(20px, 3vw, 32px); line-height: 1.45; text-align: center;
  color: rgba(248, 244, 235, 0.92); max-width: 80vw;
}

/* social links — plain monoline marks, not brand-colour logos */
.social {
  display: flex; gap: 22px; pointer-events: auto; margin-top: 4px;
}
.social a {
  color: rgba(248, 244, 235, 0.85); opacity: 0.85; transition: opacity 0.25s ease, color 0.25s ease;
  display: block; line-height: 0;
}
.social a:hover { opacity: 1; color: var(--gold); }
.social svg {
  width: 26px; height: 26px; fill: none; stroke: currentColor;
  stroke-width: 1.3; stroke-linecap: round; stroke-linejoin: round;
}

/* ── the archive: projects, drifted into rather than browsed ──
   the hero is the clear, arrived-at moment; this is a step further
   into the fog — a soft wash over the fixed photo, low contrast
   until each entry is scrolled into view and settles into focus */
.archive {
  position: relative; z-index: 1; padding: 8vh 8vw 22vh;
}
/* the wash is position:fixed (covers the whole viewport regardless
   of which section paints it) — with two .archive sections now,
   only let the first one own the pseudo-element or the opacity
   would compound when both are "visible" at once */
.archive:first-of-type::before {
  content: ''; position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background: rgba(6,6,10,0.4); backdrop-filter: blur(3px);
  opacity: 0; transition: opacity 1.2s ease;
}
body.archive-visible .archive:first-of-type::before { opacity: 1; }

.archive-head {
  position: relative; font-family: var(--mono); font-weight: 300; font-size: 11px;
  letter-spacing: 0.3em; text-transform: uppercase; color: var(--gold);
  margin-bottom: 8vh; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.7));
}

/* a book index — term, dotted leader, number. the way an index
   actually reads: nothing loose, nothing floating, entries pinned
   to a line and a number the way a real one is */
.index-list {
  list-style: none; max-width: 1500px; margin: 0 auto;
}
.index-row-item {
  border-bottom: 1px solid rgba(240,210,170,0.14);
}
.index-row-item:last-child { border-bottom: none; }

.index-row {
  display: flex; align-items: baseline; gap: 12px;
  padding: 18px 0 6px; text-decoration: none;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.7));
  opacity: 0; transform: translateY(14px);
  transition: opacity 1.1s ease, transform 1.1s ease;
}
.index-row.in { opacity: 1; transform: translateY(0); }

.index-term {
  font-family: var(--sans); font-weight: 300; white-space: nowrap;
  font-size: clamp(17px, 2vw, 21px); color: rgba(248,244,235,0.92);
  transition: color 0.25s ease;
}
.index-leader {
  flex: 1 1 auto; align-self: flex-end; min-width: 16px; margin-bottom: 5px;
  border-bottom: 1px dotted rgba(240,210,170,0.32);
  transition: border-color 0.25s ease;
}
.index-num {
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.08em;
  color: var(--gold); transition: color 0.25s ease;
}
.index-row:hover .index-term, .index-row:focus-visible .index-term { color: #fff; }
.index-row:hover .index-leader, .index-row:focus-visible .index-leader { border-color: rgba(255,255,255,0.55); }
.index-row:hover .index-num, .index-row:focus-visible .index-num { color: rgba(255,244,225,0.95); }

/* a group term — a heading the way a book index nests related
   entries under one word, indented below it rather than broken out
   into its own labelled section */
.index-group-label {
  font-family: var(--sans); font-weight: 300; font-size: clamp(17px, 2vw, 21px);
  color: rgba(248,244,235,0.92); padding: 18px 0 4px;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.7));
}
.index-sublist { list-style: none; padding-left: 26px; }
.index-sublist .index-row { padding: 10px 0 4px; }
.index-sublist .index-term { font-size: clamp(15px, 1.7vw, 18px); color: rgba(240,238,232,0.8); }
.index-sublist .index-row-item:last-child { border-bottom: 1px solid rgba(240,210,170,0.14); }
.index-list > .index-row-item:last-child,
.index-list > .index-group:last-child .index-sublist .index-row-item:last-child {
  border-bottom: none;
}

/* the note — held back until you land on the entry, so the index
   itself stays an index and not a paragraph list */
.index-note {
  margin: 0; padding: 0 0 18px; max-width: min(560px, 90%);
  font-family: var(--sans); font-weight: 300; font-size: 14px; line-height: 1.55;
  color: rgba(240,238,232,0.68); filter: drop-shadow(0 1px 2px rgba(0,0,0,0.7));
  max-height: 0; opacity: 0; overflow: hidden;
  transition: opacity 0.3s ease, max-height 0.3s ease;
}
.index-row-item:hover .index-note, .index-row-item:focus-within .index-note {
  opacity: 1; max-height: 140px;
}

@media (max-width: 640px) {
  .index-term { font-size: 17px; }
  .index-note { opacity: 1; max-height: none; padding-bottom: 16px; }
}

/* ── the captcha: a found object that doesn't belong here ──
   deliberately generic system-UI styling — the joke depends on
   it reading as the real thing before it confesses otherwise */
.captcha {
  /* true centring, not a calc()'d offset from a corner anchor — the
     old version hardcoded desktop dimensions into the math and broke
     on phones, where the width/anchor change in the media query below */
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  z-index: 2; width: 300px; max-width: 88vw;
  background: #f9f9f9; border: 1px solid #d3d3d3;
  border-radius: 3px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
  cursor: pointer; user-select: none;
  transition: opacity 0.9s ease;
  animation: captcha-breathe 3.4s ease-in-out infinite;
}
.captcha.clicked { animation: none; box-shadow: 0 1px 3px rgba(0,0,0,0.22); }
/* dissolves right where it is — no motion, no slide, no glitch */
.captcha.gone { opacity: 0; pointer-events: none; }

/* a quiet, slow pulse — the same invitation as the breath elsewhere
   on this site, just small enough here to read as "try this" */
@keyframes captcha-breathe {
  0%, 100% { box-shadow: 0 1px 3px rgba(0,0,0,0.22), 0 0 0 rgba(240,190,130,0); }
  50%      { box-shadow: 0 1px 3px rgba(0,0,0,0.22), 0 0 16px rgba(240,190,130,0.45); }
}

.captcha-row { display: flex; align-items: center; gap: 14px; padding: 16px; }
.captcha-box {
  flex: none; width: 28px; height: 28px; background: #fff;
  border: 2px solid #c1c1c1; border-radius: 2px; position: relative;
  transition: border-color 0.25s ease, background 0.25s ease;
}
.captcha-row:hover .captcha-box { border-color: #999; }

.captcha-box.checking::after {
  content: ''; position: absolute; inset: 5px; border-radius: 50%;
  border: 2px solid #4285f4; border-top-color: transparent;
  animation: captcha-spin 0.7s linear infinite;
}
@keyframes captcha-spin { to { transform: rotate(360deg); } }

.captcha-box.verified { border-color: #34a853; }
.captcha-box.verified::after {
  content: ''; position: absolute; left: 6px; top: 1px;
  width: 9px; height: 16px; border: solid #34a853;
  border-width: 0 3px 3px 0; transform: rotate(45deg);
}

.captcha-box.confessed { border-color: #d33; background: #fff5f5; }
.captcha-box.confessed::after {
  content: '?'; position: absolute; inset: 0; display: flex;
  align-items: center; justify-content: center;
  color: #d33; font-weight: 700; font-size: 15px; font-family: Arial, sans-serif;
  border: none; transform: none; width: auto; height: auto; left: 0; top: 0;
}

.captcha-label { font-size: 14px; line-height: 1.25; color: #222; transition: color 0.25s ease; }
.captcha-box.confessed ~ .captcha-label { color: #a11; font-style: italic; }

/* a loading-style ellipsis, on every line the label ever shows —
   something's always coming, even though nothing about a real
   captcha would ever say so */
.dots { display: inline-flex; gap: 3px; margin-left: 5px; vertical-align: middle; }
.dots i {
  width: 5px; height: 5px; border-radius: 50%; background: #555;
  display: inline-block; opacity: 0.3;
  animation: dot-pulse 1.2s ease-in-out infinite;
}
.dots i:nth-child(2) { animation-delay: 0.15s; }
.dots i:nth-child(3) { animation-delay: 0.3s; }
@keyframes dot-pulse {
  0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
  30%           { opacity: 1;   transform: translateY(-3px); }
}

@media (max-width: 640px) {
  .hero { gap: 20px; }
  .motto { font-size: 19px; max-width: 82vw; }
  .social { gap: 14px; }
  .social svg { width: 16px; height: 16px; }
  .captcha { width: 260px; }
}
