/* THE LONG EXPOSURE — whereishairglasses.com
   ═══════════════════════════════════════════════════════════════════

   THE CROSSOVER: hair + glasses.

     HAIR    organic, 1960s, psychedelic, warm, hand-drawn, human
     GLASSES optical, precise, cyber, cold, machine-ruled

   Every design token below picks a side. The story is a person and a
   system sharing one pair of hands, so the type system is too.

   TYPE
     Monoton    parallel-line display. Reads as both 1970s poster and
                lenticular optics. This is the GLASSES face. Wordmark + h1.
     Shrikhand  heavy psychedelic brush, rounded terminals, Fillmore-poster
                warmth. This is the HAIR face. The Operator's voice only.
     Space Mono retro-futurist monospace, space-age lineage. The machine
                and all system chrome. Everything else.

   COLOR
     Greyscale ground is the live Hairglasses palette (Black Metal /
     Marduk) on true #000000. Two accents, strictly rationed:
       teal  #5f8787  the machine speaks
       amber #c9803f  the human speaks
     They never appear in the same block. That is the whole point.
   ═══════════════════════════════════════════════════════════════════ */

@import url('https://fonts.googleapis.com/css2?family=Monoton&family=Shrikhand&family=Space+Mono:ital,wght@0,400;0,700;1,400&display=swap');

:root {
  /* ── ground: Black Metal (Marduk), true black ── */
  --void: #000000;
  --surface: #0a0a0a;
  --surface-alt: #101010;
  --border: #404040;
  --border-strong: #888888;
  --muted: #626b67;
  --dim: #8a8a8a;
  --fg: #c1c1c1;
  --bright: #e8e8e8;

  /* ── GLASSES: the machine. cold, optical. ── */
  --understudy: #5f8787;
  --understudy-dim: #3d5757;
  --understudy-ghost: #0e1616; /* contact-sheet cells before selection */

  /* ── HAIR: the human. warm, faded-poster. ── */
  --operator: #c9803f;
  --operator-dim: #6b4520;
  --operator-ghost: #1a1207; /* contact-sheet cells before selection */
  --psych: #a34d7a;   /* deep magenta. wordmark gradient only. */

  /* ── type ── */
  --display: "Monoton", "Impact", sans-serif;
  --groovy: "Shrikhand", "Georgia", serif;
  --mono: "Space Mono", "MonaspiceNe Nerd Font Mono", "SF Mono",
          "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;

  /* input placeholder: dim enough to read as absent, not as content */
  --placeholder: #2e2e2e;

  --measure: 66ch;
  --gut: clamp(1rem, 4vw, 2.5rem);
  --grain: 0.055;
}

*, *::before, *::after { box-sizing: border-box; }

html {
  background: var(--void);
  color-scheme: dark;
  scrollbar-color: var(--border) var(--void);
}

body {
  margin: 0;
  background: var(--void);
  color: var(--fg);
  font-family: var(--mono);
  font-size: clamp(0.94rem, 0.86rem + 0.42vw, 0.97rem);
  line-height: 1.75;
  letter-spacing: 0.005em;
  padding: var(--gut);
  min-height: 100vh;
  overflow-x: hidden;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

/* ═══ FILM GRAIN ═══════════════════════════════════════════════════
   Static feTurbulence, never animated: animated grain is a flicker
   hazard and costs a repaint every frame for no narrative gain.

   mix-blend-mode: overlay is load-bearing. Overlay against #000000
   resolves to #000000, so the grain sits on the mid-greys and the
   lit type while leaving the true-black ground genuinely off on an
   OLED panel. That is the entire reason this palette exists.
   ═════════════════════════════════════════════════════════════════ */

html::before {
  content: "";
  position: fixed;
  inset: -50%;
  width: 200%;
  height: 200%;
  pointer-events: none;
  z-index: 9002;
  opacity: var(--grain);
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 220px 220px;
}

/* scanlines */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9000;
  background: repeating-linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.016) 0px,
    rgba(255, 255, 255, 0.016) 1px,
    transparent 1px,
    transparent 3px
  );
}

/* vignette + a faint warm light leak from the top left,
   the one place the 60s is allowed to touch the whole page */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9001;
  background:
    radial-gradient(ellipse at 12% 0%, rgba(201, 128, 63, 0.055), transparent 46%),
    radial-gradient(ellipse at center, transparent 54%, rgba(0, 0, 0, 0.6) 100%);
}

/* ── Layout ────────────────────────────────────────────────────── */

main, .wrap { max-width: var(--measure); margin: 0 auto; position: relative; z-index: 1; }
.wide { max-width: 92ch; }

/* ── Wordmark: the crossover, stated once, at the top ──────────── */

.wordmark {
  font-family: var(--display);
  font-size: clamp(1.75rem, 0.9rem + 4.4vw, 3.7rem);
  line-height: 0.98;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  margin: 0 0 0.3rem;
  background: linear-gradient(
    100deg,
    var(--operator) 0%,
    var(--psych) 34%,
    var(--fg) 62%,
    var(--understudy) 100%
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 0 22px rgba(163, 77, 122, 0.18));
}
@supports not (background-clip: text) {
  .wordmark { color: var(--fg); -webkit-text-fill-color: currentColor; }
}

/* Two lines, one gradient box, because they are one element. Line one is the
   question and line two is the name; the amber-to-teal run crosses both. */
.wordmark .w1 { display: block; font-size: 0.56em; letter-spacing: 0.28em; }
.wordmark .w2 { display: block; }

.wordmark-sub {
  font-family: var(--groovy);
  font-size: clamp(1.15rem, 0.9rem + 0.7vw, 1.4rem);
  color: var(--operator);
  letter-spacing: 0.01em;
  margin: 0 0 2.6rem;
  opacity: 0.82;
}

/* ── Chrome: the machine's register. uppercase, tracked, small. ── */

.chrome {
  color: var(--dim);
  font-size: 0.76em;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* Historical inline declarations still name the canonical muted token. Keep
   that token available for decorative and inactive hierarchy, but route any
   readable chrome through the AA-compliant neutral ramp. */
.chrome[style*="color:var(--muted)"] { color: var(--dim) !important; }

.statusbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  justify-content: space-between;
  border-bottom: 1px solid var(--border);
  padding-bottom: 0.6rem;
  margin-bottom: 2.5rem;
  color: var(--dim);
  font-size: max(0.7em, 11px);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.statusbar b { color: var(--dim); font-weight: 400; }

footer.sysfoot {
  max-width: var(--measure);
  margin: 5rem auto 0;
  border-top: 1px solid var(--border);
  padding-top: 1rem;
  color: var(--dim);
  font-size: max(0.68em, 11px);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.5rem;
  justify-content: space-between;
}

/* ── Type ──────────────────────────────────────────────────────── */

h1 {
  font-family: var(--display);
  font-size: clamp(1.75rem, 1rem + 2.4vw, 2.6rem);
  font-weight: 400;
  letter-spacing: 0.03em;
  line-height: 1.05;
  color: var(--bright);
  text-transform: uppercase;
  margin: 0 0 0.5rem;
}

h2 {
  font-size: 0.84em;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 3rem 0 1rem;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid var(--border);
}

h3 {
  font-size: 0.82em;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 2rem 0 0.6rem;
}

.subtitle {
  font-family: var(--groovy);
  color: var(--operator);
  font-size: 1.15rem;
  letter-spacing: 0.01em;
  margin: 0 0 2.5rem;
  opacity: 0.8;
}

p { margin: 0 0 1.25rem; }
p:last-child { margin-bottom: 0; }

a {
  color: var(--fg);
  text-decoration: none;
  border-bottom: 1px solid var(--border-strong);
  transition: color 0.16s, border-color 0.16s;
}
a:hover, a:focus-visible { color: var(--bright); border-bottom-color: var(--bright); }

:focus-visible { outline: 2px solid var(--understudy); outline-offset: 3px; }

hr { border: 0; border-top: 1px solid var(--border); margin: 2.5rem 0; }

/* ═══ THE OPERATOR — hair. warm, lowercase, human. ════════════════ */

.operator { color: var(--fg); text-transform: none; }
.operator p { text-transform: lowercase; }
.operator em { color: var(--operator); font-style: normal; }

/* The Operator's first line gets the groovy face. One warm gesture at
   the top of each entry, then it hands back to the machine's mono. */
.operator > p:first-of-type {
  font-family: var(--groovy);
  font-size: 1.3rem;
  line-height: 1.5;
  color: var(--operator);
  text-transform: none;
  margin-bottom: 1.8rem;
}

.logmeta {
  color: var(--dim);
  font-size: 0.72em;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 2rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--border);
}

body[data-log-id^="operator"] .logmeta,
body[data-log-id^="operator"] .statusbar {
  border-bottom-color: var(--operator-dim);
}
body[data-log-id^="understudy"] .logmeta,
body[data-log-id^="understudy"] .statusbar {
  border-bottom-color: var(--understudy-dim);
}
body[data-log-id^="operator"] main { max-width: 68ch; }
body[data-log-id^="understudy"] main { max-width: 58ch; }

h1.op-title {
  font-family: var(--groovy);
  color: var(--operator);
  text-transform: none;
  letter-spacing: 0;
  font-size: clamp(1.5rem, 1rem + 2.6vw, 2.7rem);
  line-height: 1.12;
}

/* ═══ THE UNDERSTUDY — glasses. cold, precise, machine. ═══════════ */

.understudy, .machine { color: var(--understudy); }
.understudy p { margin-bottom: 1.25rem; }

/* The machine's opening statement occupies the same structural slot as the
   Operator's warm opener, but stays ruled, tracked, and optical. */
.understudy > p:first-of-type {
  font-size: 1.18rem;
  line-height: 1.55;
  letter-spacing: 0.06em;
  color: var(--bright);
  margin-bottom: 1.9rem;
  padding-bottom: 1.2rem;
  border-bottom: 1px solid var(--understudy-dim);
}

.machine-block {
  border-left: 2px solid var(--understudy-dim);
  padding: 0.2rem 0 0.2rem 1.4rem;
  margin: 2rem 0;
  color: var(--understudy);
}

/* Direct variants used at the two narrative turns in Act III. */
.understudy > p.machine-turn {
  border-left: 2px solid var(--understudy-dim);
  padding: 0.2rem 0 0.2rem 1.4rem;
  margin: 2rem 0;
}

.understudy > p > .machine-quote {
  display: block;
  font-family: var(--mono);
  font-size: clamp(1.05rem, 0.9rem + 1vw, 1.4rem);
  line-height: 1.55;
  letter-spacing: 0.04em;
  color: var(--understudy);
  border-top: 1px solid var(--understudy-dim);
  border-bottom: 1px solid var(--understudy-dim);
  padding: 1.6rem 0;
  margin: 3rem 0;
}

.operator-block {
  border-left: 2px solid var(--operator-dim);
  padding: 0.2rem 0 0.2rem 1.4rem;
  margin: 2rem 0;
  color: var(--operator);
}

/* ── Terminal ──────────────────────────────────────────────────── */

#terminal { min-height: 54vh; word-break: break-word; }
/* Chrome keeps its literal spacing (the dot leaders line up). Prose does not:
   hand-wrapped prose under pre-wrap wraps a second time on a narrow screen. */
#terminal .line.sys,
#terminal .line.warn,
#terminal .line.ok   { white-space: pre-wrap; }
#terminal .line.machine,
#terminal .line.usay { white-space: normal; max-width: 62ch; }

.line { margin: 0; min-height: 1.75em; }
.line.sys { color: var(--dim); letter-spacing: 0.1em; }
.line.ok { color: var(--dim); }
.line.warn { color: var(--operator); letter-spacing: 0.1em; }
.line.usay { color: var(--bright); }
.line.machine { color: var(--understudy); }

.cursor {
  display: inline-block;
  width: 0.6em;
  height: 1.05em;
  background: var(--fg);
  vertical-align: text-bottom;
  animation: blink 1.1s steps(1) infinite;
}
@keyframes blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* ── Prompt / gates ────────────────────────────────────────────── */

.prompt {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  border-top: 1px solid var(--border);
  margin-top: 2rem;
  padding-top: 1.2rem;
}
.prompt .sigil { color: var(--understudy); flex: none; }
.prompt input {
  flex: 1 1 auto;
  min-width: 0;
  background: transparent;
  border: 0;
  color: var(--bright);
  font: inherit;
  letter-spacing: 0.08em;
  padding: 0.2rem 0;
  caret-color: var(--understudy);
}
.prompt input:focus { outline: none; }
.prompt input::placeholder { color: var(--placeholder); letter-spacing: 0.14em; }

.gate {
  border: 1px solid var(--border);
  background: var(--surface);
  padding: 1.4rem var(--gut);
  margin: 2.5rem 0;
}
.gate .q {
  font-family: var(--groovy);
  color: var(--operator);
  letter-spacing: 0;
  text-transform: none;
  font-size: 1.25rem;
  margin-bottom: 0.7rem;
}
.gate .prompt { margin-top: 1rem; }
.gate[data-open="1"] { border-color: var(--understudy-dim); }
.gate-label { display: block; margin-top: 0.8rem; color: var(--dim); }

.gate-help { margin: 1rem 0 0; }
.gate-help-button {
  appearance: none;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--dim);
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  padding: 0.55rem 0.75rem;
  cursor: pointer;
}
.gate-help-button:hover,
.gate-help-button:focus-visible { color: var(--bright); border-color: var(--border-strong); }
.gate-help-button:disabled { color: var(--dim); cursor: default; opacity: 0.75; }

.hint {
  color: var(--understudy);
  font-size: 0.8em;
  letter-spacing: 0.1em;
  margin-top: 1rem;
  min-height: 1.2em;
}

.shake { animation: shake 0.3s ease; }
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-4px); }
  75% { transform: translateX(4px); }
}

.locked {
  color: var(--dim);
  border: 1px dashed var(--border);
  padding: 1.2rem var(--gut);
  margin: 2rem 0;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-size: 0.76em;
}

/* ── Index listing ─────────────────────────────────────────────── */

.index { list-style: none; padding: 0; margin: 0; }
.index li { border-bottom: 1px solid var(--border); }
.index li a, .index li .row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.2rem;
  align-items: baseline;
  padding: 0.9rem 0;
  border-bottom: 0;
}
.index .id {
  color: var(--dim);
  font-size: 0.72em;
  letter-spacing: 0.14em;
  flex: none;
  min-width: 11ch;
}
.index .title { flex: 1 1 24ch; }
.index li a .title { font-family: var(--groovy); font-size: 1.15rem; }
.index .state {
  color: var(--dim);
  font-size: max(0.68em, 11px);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.index li[data-locked="1"] { opacity: 0.4; }

/* ── Diff ──────────────────────────────────────────────────────── */

.diff {
  border: 1px solid var(--border);
  background: var(--surface);
  overflow-x: auto;
  margin: 2rem 0;
  font-size: 0.84em;
}
.diff table { border-collapse: collapse; width: 100%; min-width: 44ch; }
.diff td { padding: 0.22rem 0.7rem; vertical-align: top; }
.diff td.g {
  color: var(--dim);
  width: 8ch;
  white-space: nowrap;
  font-size: 0.78em;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  user-select: none;
  border-right: 1px solid var(--border);
  text-align: center;
}
.diff tr.add { background: rgba(95, 135, 135, 0.08); }
.diff tr.add td.g, .diff tr.add td.t { color: var(--understudy); }
.diff:focus-visible { outline: 2px solid var(--understudy); outline-offset: 3px; }
.diff-instruction { margin-bottom: -1rem; }

@media (max-width: 40rem) {
  .statusbar,
  footer.sysfoot {
    justify-content: flex-start;
    column-gap: 1rem;
  }

  .diff {
    font-size: 0.78em;
    background:
      linear-gradient(to right, var(--surface) 70%, transparent),
      linear-gradient(to left, var(--surface) 70%, transparent) 100% 0,
      radial-gradient(farthest-side at 100% 50%, rgba(95, 135, 135, 0.35), transparent),
      var(--surface);
    background-repeat: no-repeat;
    background-size: 24px 100%, 24px 100%, 14px 100%;
    background-attachment: local, local, scroll;
    scrollbar-width: thin;
  }
  .diff td { padding: 0.2rem 0.45rem; }

  /* A border-built chevron remains legible without colour and does not enter
     the accessibility tree. It marks the clipped right edge as horizontal. */
  .diff::before {
    content: "";
    display: block;
    position: sticky;
    left: calc(100% - 1.35rem);
    top: 0.6rem;
    width: 0.65rem;
    height: 0.65rem;
    margin: 0.6rem 0 -1.25rem;
    border-top: 2px solid var(--dim);
    border-right: 2px solid var(--dim);
    transform: rotate(45deg);
    pointer-events: none;
  }
}

/* ── Gallery ───────────────────────────────────────────────────── */

.plates {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(258px, 100%), 1fr));
  gap: 1.5rem;
  margin: 2rem 0;
}
.plate { border: 1px solid var(--border); background: var(--surface); overflow: hidden; }
.plate figure { margin: 0; }
.plate svg, .plate img { display: block; width: 100%; height: auto; background: #000; }
.plate figcaption { padding: 0.9rem 1rem 1.1rem; border-top: 1px solid var(--border); }
.plate .pt {
  font-family: var(--groovy);
  color: var(--fg);
  letter-spacing: 0;
  text-transform: none;
  font-size: 1.12rem;
  display: block;
  margin-bottom: 0.5rem;
}
.plate dl {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.1rem 0.8rem;
  font-size: max(0.68em, 11px);
  letter-spacing: 0.08em;
  color: var(--dim);
}
.plate dt { text-transform: uppercase; }
.plate dd { margin: 0; color: var(--dim); }

/* GATE 4. #050505 on #000000: invisible to a display, trivially
   available to select-all, view-source, devtools, reader mode, and
   every screen reader. Signposted on the page, so it is a puzzle
   rather than a trick. */
.underexposed { color: #050505; user-select: text; }
.underexposed::selection { background: var(--understudy); color: var(--void); }

/* ── Choices ───────────────────────────────────────────────────── */

/* The seam is literal. The two cases share one 1px border and nothing else:
   the grid gap IS the border colour showing through, so there is no gutter
   between them to soften the join. The whole design thesis of this site is
   that hair and glasses are two temperatures that meet at an edge, and this
   is the one place on the site where the reader has to stand on that edge. */
.choices {
  display: grid;
  gap: 1px;
  margin: 2.5rem 0;
  background: var(--border);
  border: 1px solid var(--border);
}
@media (min-width: 40rem) { .choices { grid-template-columns: repeat(auto-fit, minmax(17.5rem, 1fr)); } }

.choice {
  display: block;
  width: 100%;
  text-align: left;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--fg);
  font: inherit;
  padding: 1.5rem;
  cursor: pointer;
  transition: border-color 0.18s, background 0.18s, color 0.18s;
}
.choice:hover, .choice:focus-visible {
  border-color: var(--border-strong);
  background: var(--surface-alt);
}
.choice .ct {
  font-family: var(--groovy);
  display: block;
  letter-spacing: 0;
  text-transform: none;
  font-size: 1.3rem;
  margin-bottom: 0.6rem;
}
.choice .cd { font-size: 0.86em; color: var(--dim); line-height: 1.65; }

.choice.op-choice .ct { color: var(--operator); }
.choice.op-choice:hover, .choice.op-choice:focus-visible { border-color: var(--operator-dim); }
.choice.machine-choice .ct { color: var(--understudy); }
.choice.machine-choice:hover, .choice.machine-choice:focus-visible { border-color: var(--understudy-dim); }

/* ── Misc ──────────────────────────────────────────────────────── */

.reveal { opacity: 0; animation: fade 0.9s ease forwards; }
@keyframes fade { to { opacity: 1; } }

.progress { display: flex; gap: 0.4rem; margin: 0; padding: 0; list-style: none; }
.progress li {
  width: 2.2rem;
  min-height: 1.4rem;
  color: var(--dim);
  background: transparent;
  border-bottom: 3px solid var(--border);
  line-height: 1;
  text-align: center;
}
.progress li.on { color: var(--understudy); border-bottom-color: var(--understudy); }
.progress-label { margin: 0.55rem 0 0; color: var(--dim); }

.access-page details,
.evidence-recap {
  border: 1px solid var(--border);
  background: var(--surface);
  margin: 1rem 0;
  padding: 0.9rem var(--gut);
}
.access-page summary,
.evidence-recap summary {
  color: var(--fg);
  cursor: pointer;
  letter-spacing: 0.08em;
}
.access-page details[open] summary,
.evidence-recap[open] summary { margin-bottom: 1rem; }
.evidence-recap { margin: 2.5rem 0; }
.evidence-recap li { margin: 0.65rem 0; }

.big-quote {
  font-family: var(--groovy);
  font-size: clamp(1.15rem, 0.9rem + 1.4vw, 1.75rem);
  line-height: 1.4;
  color: var(--operator);
  margin: 3rem 0;
  text-transform: none;
}

/* ── Reduced motion + plain mode ───────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .cursor { animation: none; opacity: 1; }
  body::before { display: none; }
}

body.plain::before { display: none !important; }
body.plain::after { display: none !important; }
html:has(body.plain)::before { display: none !important; }
body.plain .reveal { opacity: 1; animation: none; }
body.plain .cursor { animation: none; }
body.plain .underexposed { color: var(--understudy); }
body.plain .wordmark {
  color: var(--fg);
  -webkit-text-fill-color: var(--fg);
  background: none;
  filter: none;
}

.skip { position: absolute; left: -9999px; }
.skip:focus {
  left: var(--gut);
  top: var(--gut);
  z-index: 10000;
  background: var(--surface);
  padding: 0.6rem 1rem;
  border: 1px solid var(--understudy);
}

.sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ── the identity plate ───────────────────────────────────────────────────
   The canvas and the static mark occupy the same square, so whichever one
   ends up visible the page does not move. A no-WebGL visitor should never
   be able to tell that something was meant to happen here.               */
.plate-bay {
  position: relative;
  width: min(280px, 58%);
  aspect-ratio: 1 / 1;
  margin: 0 auto;
}
.plate-bay > img,
.plate-bay > canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}
.plate-bay > canvas {
  /* Nothing here is interactive in the keyboard sense: the pointer only
     changes how hard it tries, and it never succeeds either way. */
  touch-action: pan-y;
}
body.plain .plate-bay > canvas { display: none !important; }

/* ── the two cases ────────────────────────────────────────────────────── */
/* No accent ever touches the seam: the panels carry surface, and only the
   type inside them is amber or teal. */
.choice {
  border: 0;
  background: var(--surface);
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
.cl {
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.op-choice .cl, .op-choice .ct { color: var(--operator); }
.machine-choice .cl, .machine-choice .ct { color: var(--understudy); }
.cact { margin-top: auto; padding-top: 0.75rem; }
.crow { display: flex; gap: 0.6rem; }

.cast {
  width: 100%;
  padding: 0.9rem 0.75rem;
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--fg);
  font: inherit;
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.18s, color 0.18s, border-color 0.18s;
}
.op-choice .cast { border-color: var(--operator); color: var(--operator); }
.machine-choice .cast { border-color: var(--understudy); color: var(--understudy); }
.op-choice .cast:hover { background: rgba(201, 128, 63, 0.12); color: var(--bright); }
.machine-choice .cast:hover { background: rgba(95, 135, 135, 0.12); color: var(--bright); }
.cast:focus-visible { outline: 2px solid var(--border-strong); outline-offset: 3px; }
.crow .cast { width: auto; flex: 1; }
.op-choice .turn { background: var(--operator); color: var(--void); }
.machine-choice .turn { background: var(--understudy); color: var(--void); }
.cast.back { border-color: var(--border); color: var(--dim); background: transparent; }
.cast.back:hover { color: var(--fg); border-color: var(--border-strong); background: transparent; }

.cnote { font-size: 0.8rem; line-height: 1.5; margin: 0 0 0.7rem; color: var(--dim); }
.op-choice .cnote.armed { color: var(--operator); }
.machine-choice .cnote.armed { color: var(--understudy); }

/* Available to assistive tech, absent from the page. Distinct from the
   contrast-hidden text on /render, which is a puzzle and must stay visible
   to anyone who selects it. This is only ever a note about the interface. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The caption never wraps. On a narrow phone it scrolls in its own track
   rather than breaking across lines or pushing the body sideways. */
.plate-bay + figcaption, figure > figcaption.chrome {
  white-space: nowrap;
  overflow-x: auto;
  padding-bottom: 0.4rem;
  scrollbar-width: thin;
}
body.plain .choices { gap: 0.75rem; background: none; border: 0; }
body.plain .choice { border: 1px solid var(--border); }

/* ── the contact sheet ────────────────────────────────────────────────────
   One cell per plate, the whole archive, drawn. It must never scroll: the
   point is meeting the volume all at once, and a sheet you scroll through
   delivers it a screenful at a time, which is the problem rather than the
   fix. */
#contact { margin: 0 0 3rem; }
#contact canvas {
  display: block;
  width: 100%;
  border: 1px solid var(--border);
  background: var(--void);
  image-rendering: pixelated;
}
#contact figcaption { margin-top: 0.7rem; }
body.plain #contact canvas { display: none !important; }

/* ── the next plate ──────────────────────────────────────────────────
   The canvas has a fixed internal plate size so an approved seed reproduces
   the same pixels on a phone and a desktop. CSS only scales the object. */
.next-plate-bay { margin: 2.5rem 0 3rem; }
.next-plate-bay > canvas,
.next-plate-static {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--border);
  background: var(--void);
}
.next-plate-bay > canvas { height: auto; }
.next-plate-static {
  min-height: 18rem;
  margin: 0;
  padding: clamp(1.25rem, 4vw, 2.5rem);
  align-content: center;
}
.next-plate-static[hidden] { display: none; }
figure.next-plate-bay > figcaption.chrome {
  margin-top: 0.7rem;
  white-space: normal;
  overflow-x: visible;
  overflow-wrap: anywhere;
  line-height: 1.7;
}
body.plain .next-plate-bay > canvas { display: none !important; }

.plate-approval { margin: 2rem 0; }
.approve-plate {
  width: 100%;
  padding: 1rem;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--fg);
  font: inherit;
  letter-spacing: 0.14em;
  cursor: pointer;
}
.approve-plate:hover { border-color: var(--fg); color: var(--bright); }
.approve-plate:focus-visible { outline: 2px solid var(--fg); outline-offset: 3px; }
.approve-plate:disabled { cursor: default; color: var(--muted); border-color: var(--border); }
.plate-totals { color: var(--dim); margin-top: 0.8rem; }

/* Amber begins only after a human judgement, in a separate block below the
   teal-bearing render. The two accents never occupy one block. */
.approval-stamp {
  border: 1px solid var(--operator);
  color: var(--operator);
  padding: 1rem 1.25rem;
  margin: 1.5rem 0 3rem;
}
.approval-stamp p { margin: 0; color: var(--operator); }

/* The loop noticing a return. Sits above the archive nav, in the machine's
   own register, and deliberately carries no dismiss control: it is a log
   entry, not a notification. */
.revisit { margin: 2.5rem 0 0; }
.revisit b { color: var(--understudy); font-weight: 400; }

/* ── Wave 2 interaction surfaces ────────────────────────────────────────── */
.blind-test {
  margin: 4rem 0;
  padding: 0 0 2rem;
  border-bottom: 1px solid var(--border);
}
.blind-test canvas,
.blind-fallback {
  display: block;
  width: 100%;
  aspect-ratio: 12 / 7;
  border: 1px solid var(--border);
  background: var(--void);
}
.blind-test canvas { height: auto; image-rendering: pixelated; }
.blind-fallback {
  padding: 2rem;
  color: var(--dim);
  align-content: center;
  letter-spacing: 0.12em;
  text-align: center;
}
.blind-fallback[hidden] { display: none; }
.blind-actions,
.approval-pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
  margin-top: 1rem;
}
.blind-actions button,
.plate-call {
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--fg);
  font: inherit;
  padding: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  cursor: pointer;
}
.blind-actions button:hover,
.plate-call:hover { color: var(--bright); border-color: var(--fg); }
.plate-call:disabled { cursor: default; color: var(--muted); border-color: var(--border); }
.approval-pair { padding: 0 1rem 1rem; align-items: center; }
.plate-call-state { grid-column: 1 / -1; text-align: center; }
body.plain .blind-test canvas { display: none !important; }
body.plain .blind-fallback { display: block !important; }

.operator-notes {
  list-style: decimal-leading-zero;
  padding-left: 3.5rem;
  margin: 2rem 0;
}
.operator-notes li { padding: 0.45rem 0 0.45rem 0.7rem; border-bottom: 1px solid var(--border); }
.operator-notes li::marker { color: var(--muted); font-family: var(--mono); }

.november-room { margin: 2.5rem 0; }
.november-room img {
  display: block;
  width: 100%;
  height: auto;
  filter: grayscale(1) contrast(1.02);
  border: 1px solid var(--border);
}
.november-room figcaption { margin-top: 0.7rem; }
.wall-labels > section {
  border-bottom: 1px solid var(--border);
  padding: 0.25rem 0 1.25rem;
}
.wall-labels h3 { color: var(--understudy); }
.plate-1205 { width: min(560px, 100%); margin: 3rem auto; }
.plate-1205 img { display: block; width: 100%; height: auto; }
.plate-1205 figcaption { margin-top: 0.8rem; text-align: center; }

/* The two Act VI branches are colour negatives. The restored room contains
   no machine teal; the continued room contains no human amber. */
body[data-act-six-ending="restore"] :focus-visible { outline-color: var(--operator); }
body[data-act-six-ending="restore"]::after {
  background: radial-gradient(ellipse at center, transparent 54%, rgba(0, 0, 0, 0.6) 100%);
}
body[data-act-six-ending="continue"]::after {
  background: radial-gradient(ellipse at center, transparent 54%, rgba(0, 0, 0, 0.6) 100%);
}
body[data-act-six-ending="continue"] :focus-visible { outline-color: var(--understudy); }

/* ── the reader's own light ────────────────────────────────────────────────
   /render says some exposures require more light than your display provides.
   A reader who has asked their operating system for more contrast has already
   supplied it. The mechanism is the sentence, which is the only kind of secret
   worth putting on this site.

   This is a reveal, not a leak: the paragraph is already free to a screen
   reader, so honouring the same request for a sighted reader who needs it is
   the accessible behaviour AND the easter egg at once. gate_hidden_text
   sanctions this context by name. */
@media (prefers-contrast: more) {
  .underexposed { color: var(--dim); }
}

/* ── print is the approval sheet ───────────────────────────────────────────
   The loop can render anything and cannot sign anything. Paper is where that
   stops being an argument and becomes a blank line.

   Browsers do not print background colours by default, so a true-black site
   prints as invisible grey-on-white unless every colour is restated. Print is
   also the one context where the underexposed paragraph must be legible: its
   contrast was chosen against a display's black level, and paper has none. */
@media print {
  html, body { background: #ffffff !important; color: #000000 !important; }
  html::before, html::after, body::before, body::after { display: none !important; }

  main, .operator, .operator-block, .machine-block, .understudy,
  p, li, h1, h2, h3, figcaption { color: #000000 !important; }

  .underexposed { color: #000000 !important; }

  a { color: #000000 !important; text-decoration: underline; }
  a[href^="/"]::after { content: " (whereishairglasses.com" attr(href) ")"; font-size: 0.8em; }

  /* Chrome that means nothing on paper. Never a voice container: a printed
     page must be a complete document, and gate_print_parity enforces that. */
  .gate, .skip, nav, .sysfoot, .statusbar, canvas, .plate-bay > canvas,
  #reset, .cast, .cact { display: none !important; }

  #contact, figure { break-inside: avoid; }

  main::after {
    display: block;
    margin-top: 3rem;
    padding-top: 1rem;
    border-top: 1px solid #000000;
    font-family: var(--mono);
    font-size: 9pt;
    white-space: pre-line;
    content: "THE LONG EXPOSURE IS A WORK OF FICTION. NOBODY WAS MISSING.\A whereishairglasses.com\A\A RENDERED BY .......................................\A APPROVED BY .......................................";
  }
}
