/* ─────────────────────────────────────────────────────────────
   living interface — dark field, Fixel type, monochrome UI.
   the only colour lives inside the particle form.
   ───────────────────────────────────────────────────────────── */

@font-face {
  font-family: 'Fixel Display';
  src: url('../assets/fonts/FixelDisplay-Regular.otf') format('opentype');
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: 'Fixel Display';
  src: url('../assets/fonts/FixelDisplay-Medium.otf') format('opentype');
  font-weight: 500; font-display: swap;
}
@font-face {
  font-family: 'Fixel Display';
  src: url('../assets/fonts/FixelDisplay-SemiBold.otf') format('opentype');
  font-weight: 600; font-display: swap;
}
@font-face {
  font-family: 'Fixel Display';
  src: url('../assets/fonts/FixelDisplay-Bold.otf') format('opentype');
  font-weight: 700; font-display: swap;
}

:root {
  --bg: #0a0a0d;
  --ink: #e8e4da;
  --ink-dim: rgba(232, 228, 218, 0.55);
  --ink-faint: rgba(232, 228, 218, 0.30);
  --line: rgba(232, 228, 218, 0.13);
  --mono: 'IBM Plex Mono', ui-monospace, monospace;
  --sans: 'Fixel Display', 'Inter', system-ui, sans-serif;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

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

html, body {
  height: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  overflow: hidden;
}

button { background: none; border: none; color: inherit; font: inherit; cursor: pointer; }
a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--line); transition: border-color 0.4s; }
a:hover { border-bottom-color: var(--ink-dim); }
.hidden { display: none !important; }
::selection { background: rgba(232, 228, 218, 0.22); }

/* ── layers ─────────────────────────────────────────────────── */

#scene { position: fixed; inset: 0; width: 100%; height: 100%; display: block; }

#vignette {
  position: fixed; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse 110% 90% at 50% 45%,
              transparent 55%, rgba(0, 0, 0, 0.55) 100%);
}

#grain {
  position: fixed; inset: -50%; pointer-events: none; opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)' opacity='0.6'/%3E%3C/svg%3E");
  animation: grain 9s steps(6) infinite;
}
@keyframes grain {
  0%,100% { transform: translate(0,0); } 20% { transform: translate(-4%,3%); }
  40% { transform: translate(3%,-2%); } 60% { transform: translate(-2%,-4%); }
  80% { transform: translate(4%,2%); }
}

/* ── corners ────────────────────────────────────────────────── */

.corner {
  position: fixed; z-index: 50;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  color: var(--ink-faint);
}
.corner.tl { top: 28px; left: 34px; }
.corner.tr { top: 28px; right: 34px; }
.corner.br { bottom: 26px; right: 34px; text-align: right;
  z-index: 30;   /* telemetry yields to the chapter sheet, same as the hint */
}

#lang button { color: var(--ink-faint); letter-spacing: 0.14em; transition: color 0.4s; padding: 4px 2px; }
#lang button.on { color: var(--ink); }
#lang i { font-style: normal; margin: 0 4px; opacity: 0.5; }

#telemetry { display: flex; flex-direction: column; gap: 5px; line-height: 1; }
#telemetry span, .corner { text-shadow: 0 0 8px rgba(10, 10, 13, 0.9); }

/* ── center blocks: invite / denied / failed ────────────────── */

.center-block {
  position: fixed; inset: 0; z-index: 20;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 34px; text-align: center; padding: 0 8vw;
  animation: rise 1.4s var(--ease);
}
@keyframes rise { from { opacity: 0; transform: translateY(14px); } }

.center-block h1 {
  font-weight: 500; font-size: clamp(26px, 3.1vw, 42px);
  letter-spacing: -0.01em; max-width: 22ch; line-height: 1.22;
}

.center-block .small {
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.06em;
  color: var(--ink-dim); max-width: 52ch; line-height: 1.8;
}

/* the hands annotation on the invite: second-level, outside the narrative —
   a hairline sets it apart (the one divider this design speaks). Second
   level by SIZE, not by fading: ink-faint drowned in the particle field */
#invite-s2 {
  margin-top: 6px; padding-top: 16px;
  border-top: 1px solid var(--line);
  color: var(--ink-dim); font-size: 11px; max-width: 50ch;
  text-shadow: 0 0 8px rgba(10, 10, 13, 0.9);
}

.mini-links { display: flex; gap: 28px; font-family: var(--mono); font-size: 13px; }
.mini-links a { color: var(--ink-dim); padding-bottom: 2px; }
.mini-links a:hover { color: var(--ink); }

.ghost {
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.1em;
  color: var(--ink-faint); transition: color 0.4s;
}
.ghost:hover { color: var(--ink-dim); }

/* asleep = quiet mouse mode: the message floats, the portfolio stays usable */
#asleep.quiet { pointer-events: none; gap: 20px; }
#asleep.quiet h1 { font-size: clamp(20px, 2vw, 28px); max-width: 26ch; }
#asleep.quiet .small { max-width: 46ch; }
#asleep.quiet .ghost, #asleep.quiet a { pointer-events: auto; }
body.space-open #asleep { opacity: 0; pointer-events: none !important; transition: opacity 0.5s; }

/* the iris — invitation to be seen */
.iris {
  display: flex; flex-direction: column; align-items: center; gap: 20px;
  color: var(--ink-dim); font-family: var(--mono); font-size: 13px; letter-spacing: 0.22em;
  transition: color 0.6s;
}
.iris svg { width: 92px; height: 92px; overflow: visible; }
.iris circle { fill: none; stroke: var(--ink-dim); }
.iris-outer { stroke-width: 0.75; opacity: 0.55; animation: dilate 5s ease-in-out infinite; transform-origin: center; }
.iris-inner { stroke-width: 1.25; animation: pulse 5s ease-in-out infinite; transform-origin: center; }
@keyframes dilate { 0%,100% { transform: scale(1); opacity: 0.35; } 50% { transform: scale(1.06); opacity: 0.7; } }
@keyframes pulse  { 0%,100% { transform: scale(1); } 50% { transform: scale(0.82); } }
.iris:hover { color: var(--ink); }
.iris:hover circle { stroke: var(--ink); }

/* ── identity ───────────────────────────────────────────────── */

#identity {
  position: fixed; left: 34px; bottom: 36px; z-index: 25;
  padding: 18px 26px 14px 0;
  background: radial-gradient(ellipse at 20% 80%, rgba(10, 10, 13, 0.72), transparent 75%);
  opacity: 0; transform: translateY(10px);
  transition: opacity 1.6s var(--ease), transform 1.6s var(--ease);
  pointer-events: none;
}
body.named #identity { opacity: 1; transform: none; }

#identity-name {
  font-size: clamp(34px, 4.2vw, 58px); font-weight: 600; letter-spacing: -0.02em;
  line-height: 1.02;
}
#identity-role {
  margin-top: 10px; font-family: var(--mono); font-size: 12px;
  letter-spacing: 0.1em; color: var(--ink-dim);
}

/* ── content nodes ──────────────────────────────────────────── */

#nodes { position: fixed; inset: 0; z-index: 24; pointer-events: none;
  transition: opacity 0.55s ease; }
/* while the form is briefly words, the words hold the whole stage */
body.glyph-on #nodes { opacity: 0; }

.node {
  position: absolute; left: 0; top: 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
  pointer-events: auto; text-align: left;
  opacity: 0; transition: opacity 1.1s var(--ease);
  will-change: transform;
}
.node.shown { opacity: 0.72; }
.node .n-label {
  transition: transform 0.45s var(--ease), color 0.45s;
  font-family: var(--mono); font-size: 13px; letter-spacing: 0.16em;
  color: var(--ink); white-space: nowrap;
  padding: 2px 0;
  border-bottom: 1px solid transparent;
  transition: border-color 0.7s, letter-spacing 0.7s;
  text-shadow: 0 0 10px rgba(10, 10, 13, 0.95), 0 0 22px rgba(10, 10, 13, 0.8);
}
.node .n-sub {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em;
  color: var(--ink-dim); white-space: nowrap;
  opacity: 0; transform: translateY(-2px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
  text-shadow: 0 0 10px rgba(10, 10, 13, 0.95);
}
.node::before {
  content: ''; position: absolute; inset: -16px -26px; z-index: -1;
  background: radial-gradient(ellipse at 30% 50%, rgba(10, 10, 13, 0.8), transparent 72%);
  filter: blur(4px);
}
.node .n-bar {
  display: block; height: 3px; width: 100%;
  margin-top: 2px;
  background: rgba(232, 228, 218, 0.18);
  opacity: 0; transition: opacity 0.35s;
  overflow: hidden;
}
.node.focus .n-bar { opacity: 1; }
.node .n-fill {
  display: block; height: 100%; width: 100%;
  background: var(--ink);
  transform: scaleX(0); transform-origin: left center;
}
.node.focus { opacity: 1; }
.node .n-label { transform-origin: left bottom; }
.node.focus .n-label {
  color: #fff;
  transform: scale(1.12);
  text-shadow: 0 0 14px rgba(10, 10, 13, 1), 0 0 30px rgba(232, 228, 218, 0.25);
}
.node.focus::before { opacity: 1.6; }
.node.pulse .n-label { animation: nodepulse 1.5s var(--ease); }
@keyframes nodepulse {
  0%, 100% { letter-spacing: 0.16em; opacity: 1; }
  40% { letter-spacing: 0.3em; opacity: 0.55; }
}
.node.focus .n-label { border-bottom-color: rgba(232, 228, 218, 0.55); letter-spacing: 0.22em; }
.node.focus .n-sub { opacity: 1; transform: none; }

/* the mouse gets a real hover — the same presence the hand focus has,
   minus the dwell bar (a click is instant, nothing fills). Both sub
   texts share one grid cell so the node's box never changes: the
   mouse reads the chapter's description, the hand reads the teaching
   hint until the first learned open (body.gl-open). */
.node .n-sub { display: grid; }
.node .n-sub > span { grid-area: 1 / 1; visibility: hidden; }
.node:hover { opacity: 1; }
.node:hover .n-label { border-bottom-color: rgba(232, 228, 218, 0.55); letter-spacing: 0.22em; }
.node:hover::before { opacity: 1.6; }
.node:hover .n-sub { opacity: 1; transform: none; }
.node:hover .n-sub > .s-d { visibility: visible; }
.node.focus .n-sub > .s-d { visibility: visible; }
body:not(.gl-open) .node.focus .n-sub > .s-h { visibility: visible; }
body:not(.gl-open) .node.focus .n-sub > .s-d { visibility: hidden; }
.is-mobile .node .n-sub > .s-d { visibility: visible; }

body.space-open .node { opacity: 0 !important; pointer-events: none; }
body.space-open #identity { opacity: 0.1; }

/* ── content space ──────────────────────────────────────────── */

#space { position: fixed; inset: 0; z-index: 35; pointer-events: none; }

#space-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(100deg,
    rgba(10, 10, 13, 0.94) 0%,
    rgba(10, 10, 13, 0.82) 34%,
    rgba(10, 10, 13, 0.35) 58%,
    transparent 78%);
  opacity: 0; transition: opacity 0.9s var(--ease);
}
body.space-open #space-scrim { opacity: 1; }
/* the sheet layer sits ABOVE the hint (z35 > z30) but must not swallow its
   clicks: only the content itself takes events — the empty field around the
   column stays transparent to the mouse, so the hint opens without closing
   the chapter (and a click into the void still reads as click-out below) */
body.space-open #space-inner { pointer-events: auto; }
body.is-mobile.space-open #space { pointer-events: auto; }

#space-scroll {
  position: absolute; left: 0; top: 0; bottom: 0; right: 0;
  overflow: hidden;
}
#space-inner {
  position: relative;
  padding: 15vh 0 22vh 7.5vw;
  width: min(46vw, 640px);
  will-change: transform;
}
body.space-right #space-scrim {
  background: linear-gradient(-100deg,
    rgba(10, 10, 13, 0.94) 0%,
    rgba(10, 10, 13, 0.82) 34%,
    rgba(10, 10, 13, 0.35) 58%,
    transparent 78%);
}
body.space-right #space-inner {
  margin-left: auto;
  padding: 15vh 7.5vw 22vh 0;
}
body.space-right #space-inner .strip {
  margin-left: calc(min(46vw, 640px) - 82vw - 7.5vw);
}

.blk {
  opacity: 0; transform: translateY(26px);
  transition: opacity 0.9s var(--ease), transform 0.9s var(--ease);
  transition-delay: 0s;
}
body.space-open .blk {
  opacity: 1; transform: none;
  transition-delay: calc(var(--i) * 80ms + 200ms);
}

#space-inner .kicker {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.22em;
  color: var(--ink-faint); margin-bottom: 20px; text-transform: lowercase;
}
#space-inner h2 {
  font-weight: 600; font-size: clamp(30px, 2.9vw, 46px); line-height: 1.08;
  letter-spacing: -0.02em; margin-bottom: 34px;
}
#space-inner h3 {
  font-family: var(--mono); font-size: 11px; font-weight: 500;
  letter-spacing: 0.22em; text-transform: lowercase;
  color: var(--ink-dim); margin: 34px 0 10px;
}
#space-inner p {
  font-size: 16px; font-weight: 400; line-height: 1.68;
  color: var(--ink); margin-bottom: 14px; max-width: 58ch;
}
#space-inner p.aside {
  font-family: var(--mono); font-size: 12px; line-height: 1.8;
  color: var(--ink-dim); margin-top: 28px; max-width: 52ch;
}

#space-inner .metrics { display: flex; flex-direction: column; gap: 0; margin: 6px 0 26px; }
#space-inner .metrics div {
  display: flex; align-items: baseline; gap: 18px;
  border-bottom: 1px solid var(--line); padding: 13px 0;
}
#space-inner .metrics b {
  font-size: 26px; font-weight: 600; letter-spacing: -0.01em; white-space: nowrap;
}
#space-inner .metrics span {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em;
  color: var(--ink-dim); line-height: 1.5;
}

#space-inner .timeline { list-style: none; margin: 4px 0 26px; }
#space-inner .timeline li {
  display: flex; flex-direction: column; gap: 3px;
  border-bottom: 1px solid var(--line); padding: 15px 0;
}
#space-inner .timeline i {
  font-family: var(--mono); font-style: normal; font-size: 11px;
  letter-spacing: 0.1em; color: var(--ink-faint);
}
#space-inner .timeline b { font-weight: 600; font-size: 16px; }
#space-inner .timeline span {
  font-family: var(--mono); font-size: 11px; color: var(--ink-dim); letter-spacing: 0.04em;
}

#space-inner .links { list-style: none; display: flex; flex-direction: column; gap: 15px; margin: 8px 0 20px; }
#space-inner .links a { font-size: 17px; font-weight: 400; border-bottom-color: var(--line); padding-bottom: 3px; }
#space-inner a.dl-got {
  animation: dlgot 1.4s var(--ease);
}
@keyframes dlgot {
  0% { border-bottom-color: var(--ink); letter-spacing: 0.04em; opacity: 1; }
  30% { letter-spacing: 0.08em; opacity: 0.6; }
  100% { border-bottom-color: var(--line); letter-spacing: 0; opacity: 1; }
}

#space-inner.page-grabbed .blk { transition: none; }

/* photo strips — draggable matter, escaping the text column */
#space-inner .strip {
  width: 82vw; margin: 26px 0 30px;
  overflow: visible; position: relative;
  cursor: grab;
}
#space-inner .strip.dragging { cursor: grabbing; }
#space-inner .strip-track {
  display: flex; gap: 20px; will-change: transform; width: max-content;
}
#space-inner .strip figure { flex: none; }
#space-inner .strip-track { --tilt: 0; }
#space-inner .strip figure {
  cursor: pointer;
  transform: perspective(1100px) rotateY(calc(var(--tilt) * 1deg)) translateY(var(--lift, 0px));
  transition: transform 0.25s ease-out;
}
#space-inner .strip figure:hover { --lift: -4px; }
#space-inner .strip img {
  height: 38vh; max-height: 420px; width: auto; display: block;
  border-radius: 2px;
  filter: saturate(0.92);
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.5);
  pointer-events: none; user-select: none;
}
#space-inner .strip figcaption {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em;
  color: var(--ink-faint); margin-top: 10px; max-width: 40ch; line-height: 1.6;
}

/* the close cross: capital-letter-sized ×, inward of the column beside
   the title (within the hand's reach); label + fill bar bloom on focus */
#space-close {
  /* lives INSIDE the scrolling sheet, beside the title: it moves with the
     text, so photos can never slide underneath it — and a brush-down
     already flies you home to where it waits */
  position: absolute; z-index: 5;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  opacity: 0; pointer-events: none;
  transition: opacity 0.7s var(--ease) 0.4s;
  cursor: pointer;
}
#space-close::before {
  content: ''; position: absolute; inset: -22px -30px; z-index: -1;
  background: radial-gradient(ellipse, rgba(10, 10, 13, 0.75), transparent 72%);
  filter: blur(4px);
}
body.space-open #space-close { opacity: 0.58; pointer-events: auto; }
body.space-open #space-close:hover,
body.space-open #space-close.focus { opacity: 1; }

#space-close svg {
  width: var(--cross, clamp(30px, 2.9vw, 46px));
  height: var(--cross, clamp(30px, 2.9vw, 46px));
  overflow: visible;
  transition: transform 0.45s var(--ease);
}
#space-close svg line {
  stroke: var(--ink-dim); stroke-width: 1.3; stroke-linecap: round;
  transition: stroke 0.3s;
}
#space-close:hover svg line, #space-close.focus svg line { stroke: var(--ink); }
#space-close:hover svg, #space-close.focus svg { transform: scale(1.1) rotate(90deg); }
#space-close .n-label {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.18em;
  color: var(--ink-dim);
  opacity: 0; transform: translateY(-3px);
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
  text-shadow: 0 0 10px rgba(10, 10, 13, 0.9);
}
#space-close .n-bar { width: 100%; }
#space-close:hover .n-label, #space-close.focus .n-label { opacity: 1; transform: none; }
#space-close.focus .n-bar { opacity: 1; }

/* thin position hint: flares up the moment the text is gripped */
#scroll-hint {
  position: absolute; top: 15vh; bottom: 18vh; width: 2px;
  left: calc(7.5vw - 26px);            /* outer edge — never under the photos */
  background: rgba(232, 228, 218, 0.08);
  opacity: 0; transition: opacity 0.3s;
  pointer-events: none;
}
body.space-right #scroll-hint {
  left: auto; right: calc(7.5vw - 26px);
}
#scroll-hint.full i { opacity: 0.3; }   /* whole chapter fits — nothing to scroll */
#scroll-hint.on { opacity: 1; }
#scroll-hint i {
  position: absolute; left: 0; width: 100%;
  background: var(--ink); opacity: 0.7;
}

/* ── hand cursor ────────────────────────────────────────────── */

#cursor {
  position: fixed; left: 0; top: 0; z-index: 80; pointer-events: none;
  width: 48px; height: 48px; margin: -24px 0 0 -24px;
  opacity: 0; transition: opacity 0.5s;
  will-change: transform;
}
body.cursor-on #cursor { opacity: 1; }
#cursor svg { width: 100%; height: 100%; overflow: visible; }
#cursor circle { fill: none; }
#cursor .c-ring {
  stroke: rgba(232, 228, 218, 0.75); stroke-width: 1.1;
  transition: r 0.15s;
}
#cursor .c-dot { fill: rgba(232, 228, 218, 0.9); }
#cursor .c-prog {
  stroke: rgba(232, 228, 218, 0.9); stroke-width: 1.4;
  stroke-dasharray: 119.4; stroke-dashoffset: 119.4;
  transform: rotate(-90deg); transform-origin: center;
}
#cursor.m-grab .c-ring { stroke: var(--ink); }
#cursor.m-grab svg { transform: scale(0.68); }
#cursor.m-palm svg { transform: scale(1.12); }
#cursor.m-point svg { transform: scale(0.88); }
#cursor.on-target .c-dot { r: 4; }
#cursor.on-target .c-ring { stroke: var(--ink); }
#cursor svg { transition: transform 0.18s var(--ease); }

/* ── lightbox ───────────────────────────────────────────────── */

#lightbox {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: rgba(6, 6, 8, 0.88);
  opacity: 0; pointer-events: none;
  transition: opacity 0.5s var(--ease);
}
body.lb-open #lightbox { opacity: 1; pointer-events: auto; }
#lightbox figure { display: flex; flex-direction: column; gap: 14px; align-items: center; max-width: 86vw; position: relative; }
#lightbox img {
  max-width: 86vw; max-height: 76vh; display: block;
  box-shadow: 0 30px 120px rgba(0, 0, 0, 0.7);
  border-radius: 2px;
}
#lightbox #lb-img { transition: opacity 0.25s; }
#lightbox img.lb-anim { animation: lbin 0.45s var(--ease); }
@keyframes lbin { from { opacity: 0; transform: scale(0.96); } }
#lightbox img.lb-from-r { animation: lbr 0.55s var(--ease); }
#lightbox img.lb-from-l { animation: lbl 0.55s var(--ease); }
@keyframes lbr { from { opacity: 0; transform: translateX(110px) scale(0.97); } }
@keyframes lbl { from { opacity: 0; transform: translateX(-110px) scale(0.97); } }
#lightbox img.lb-nudge-r { animation: lbnr 0.4s var(--ease); }
#lightbox img.lb-nudge-l { animation: lbnl 0.4s var(--ease); }
@keyframes lbnr { 30% { transform: translateX(-30px); } }
@keyframes lbnl { 30% { transform: translateX(30px); } }

#debug-tools {
  position: fixed; left: 34px; top: 56px; z-index: 90;
  display: flex; gap: 8px;
}
#debug-tools button {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em;
  color: var(--ink); background: rgba(10, 10, 13, 0.85);
  border: 1px solid var(--line); padding: 7px 12px; cursor: pointer;
}
#debug-tools button:hover { border-color: var(--ink-dim); }
#debug.mini { max-width: 320px; opacity: 0.85; }

.lb-ghost {
  position: absolute; max-width: 86vw; max-height: 76vh;
  border-radius: 2px; pointer-events: none;
  transition: transform 0.5s var(--ease), opacity 0.5s var(--ease);
}
#lightbox figcaption {
  display: flex; gap: 26px; align-items: baseline;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em;
  color: var(--ink-dim); max-width: 70ch; line-height: 1.6;
}
#lightbox #lb-count { color: var(--ink-faint); white-space: nowrap; }

/* ── debug ──────────────────────────────────────────────────── */

#debug {
  position: fixed; left: 34px; top: 92px; z-index: 90;
  font-family: var(--mono); font-size: 11px; line-height: 1.7;
  color: var(--ink-dim); white-space: pre;
  background: rgba(10, 10, 13, 0.75); padding: 12px 16px;
  border: 1px solid var(--line);
}

/* ── mobile dead-end ────────────────────────────────────────── */

body.is-mobile { overflow: auto; }
#mobile {
  position: fixed; inset: 0; z-index: 100; background: var(--bg);
  display: flex; align-items: center; justify-content: center;
  padding: 32px;
}
.m-inner { display: flex; flex-direction: column; gap: 28px; max-width: 34ch; }
#mobile h1 { font-weight: 500; font-size: 30px; line-height: 1.22; letter-spacing: -0.01em; }
#mobile p { font-family: var(--mono); font-size: 13px; line-height: 1.8; color: var(--ink-dim); }
.m-id { display: flex; flex-direction: column; gap: 6px; border-top: 1px solid var(--line); padding-top: 24px; }
.m-id span:first-child { font-weight: 600; font-size: 19px; }
.m-id span:last-child { font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em; color: var(--ink-dim); }
#mobile .mini-links { flex-wrap: wrap; gap: 20px; }

/* ── misc ───────────────────────────────────────────────────── */

#cam { position: fixed; width: 2px; height: 2px; opacity: 0; pointer-events: none; left: -10px; top: -10px; }

@media (prefers-reduced-motion: reduce) {
  #grain { animation: none; }
  .iris-outer, .iris-inner { animation: none; }
}

/* ── the mobile degradation: the same portfolio, reflowed ─────────────
   (owner's call, 09.07). Below the gate no camera ever starts; taps land
   on the mouse fallbacks, the finger scrolls real overflow; the particle
   field stays as a dormant backdrop. Only the mirror is absent. */
body.is-mobile { overflow-y: auto; overflow-x: hidden; }
.is-mobile #identity {
  position: relative; z-index: 5;   /* above the fixed canvas backdrop */
  left: auto; bottom: auto;         /* the desktop corner must not leak */
  opacity: 1; transform: none;
  padding: 96px 22px 4px; background: none; pointer-events: auto;
}
.is-mobile #identity-name { font-size: clamp(34px, 9vw, 44px); }
.is-mobile #nodes {
  position: relative; z-index: 5; inset: auto; pointer-events: auto;
  display: flex; flex-direction: column;
  padding: 22px 12px 56px;
}
.is-mobile .node {
  position: static; transform: none !important;
  padding: 16px 10px; gap: 5px;
  border-bottom: 1px solid var(--line);
}
.is-mobile .node:first-child { border-top: 1px solid var(--line); }
.is-mobile .node .n-bar { display: none; }
.is-mobile .node .n-sub { opacity: 1; transform: none; white-space: normal; }
.is-mobile #space-scroll { overflow-y: auto; -webkit-overflow-scrolling: touch; }
.is-mobile #space-inner {
  width: auto; max-width: 640px;
  padding: 11vh 22px 16vh !important; margin: 0 !important;
  transform: none !important;
}
.is-mobile #space-scrim { background: rgba(10, 10, 13, 0.96) !important; }
.is-mobile #space-inner .strip {
  width: auto; overflow-x: auto; -webkit-overflow-scrolling: touch;
  cursor: default; margin-right: -22px; padding: 4px 22px 10px 0;
}
.is-mobile #space-inner .strip { margin-left: 0 !important; }
.is-mobile #space-inner .strip img { height: 30vh; max-height: 320px; }
.is-mobile #space-inner .strip-track { transform: none !important; }
.is-mobile #cursor, .is-mobile #telemetry, .is-mobile #scroll-hint,
.is-mobile #mobile { display: none !important; }
.is-mobile #space-close { padding: 10px; }
.is-mobile #lightbox figure { max-width: 94vw; }
.is-mobile #lightbox img { max-width: 94vw; height: auto; max-height: 64vh; }
/* the close cross rides the title's line on desktop (JS-measured); on the
   phone that lands past the right edge — it pins to the corner instead */
.is-mobile #space-close {
  position: fixed !important;
  top: 20px !important; left: auto !important; right: 16px !important;
}
.is-mobile #lightbox { background: rgba(10, 10, 13, 0.94); }

/* mobile note under the role: the full experience lives on desktop */
#mobile-note { display: none; }
.is-mobile #mobile-note {
  display: block; margin-top: 20px; padding-top: 14px;
  border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.06em;
  line-height: 1.8; color: var(--ink-dim); max-width: 46ch;
}

/* mobile chapters read as modal sheets: a fixed bar holds the facet's
   name and the close cross while the content scrolls beneath */
#space-bar { display: none; }
.is-mobile #space-bar {
  display: flex; align-items: center;
  position: fixed; top: 0; left: 0; right: 0; height: 54px;
  padding: 0 60px 0 22px; z-index: 40;
  background: rgba(10, 10, 13, 0.92);
  border-bottom: 1px solid var(--line);
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.16em;
  color: var(--ink);
  opacity: 0; transition: opacity 0.4s; pointer-events: none;
}
body.is-mobile.space-open #space-bar { opacity: 1; }
.is-mobile #space-close {
  /* centred on the bar's single line: fixed glyph size (no JS measuring
     on mobile), the desktop label/bar children hidden */
  --cross: 22px;
  top: 10px !important; right: 14px !important; z-index: 41;
  padding: 6px;
}
.is-mobile #space-close .n-label,
.is-mobile #space-close .n-bar { display: none; }
.is-mobile #space-inner { padding-top: 84px !important; }
/* the corners yield to the modal bar: dimbo and the language switch would
   double the header and sit on the cross */
body.is-mobile.space-open .corner.tl,
body.is-mobile.space-open .corner.tr {
  opacity: 0; pointer-events: none; transition: opacity 0.3s;
}
/* on touch there is no dwell to bloom the cross — it must simply be seen */
.is-mobile #space-close svg line { stroke: var(--ink-dim); }

/* ── the gesture hint: amber, the form's own accent (#d9a35d) ─────────
   a toggle above, a terse technical list below — readable, unlike the
   telemetry it echoes */
#ghint {
  /* UNDER the chapter content (z35): a strip photo sliding beneath an
     overlaying hint read as debris — the sheet now covers both quiet
     corners (owner's call, 09.07) */
  position: fixed; top: 62px; right: 34px; z-index: 30;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em;
  text-align: right;
  text-shadow: 0 0 8px rgba(10, 10, 13, 0.95), 0 0 18px rgba(10, 10, 13, 0.8);
  transition: opacity 0.4s;
}
#ghint.left { right: auto; left: 34px; text-align: left; }
#ghint-t {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.16em;
  color: rgba(217, 163, 93, 0.75); padding: 4px 0;
  transition: color 0.3s;
}
#ghint-t:hover { color: #d9a35d; }
#ghint ul { list-style: none; margin-top: 4px; display: none; }
#ghint.open ul { display: block; }
#ghint.open #ghint-t { color: #d9a35d; }
/* one pattern per line, borrowed from the chapters' own metrics: the
   gesture bright, the outcome dim; amber stays a MARK (toggle + group
   headers), not a text colour — as on the form, where amber lives only
   on the nearest depth band */
#ghint li { line-height: 1.75; color: var(--ink-dim); white-space: nowrap; }
#ghint li b { font-weight: 400; color: var(--ink); }
#ghint li.gh-h {
  color: rgba(217, 163, 93, 0.85); font-size: 10px;
  letter-spacing: 0.22em; margin: 12px 0 2px;
}
#ghint li.gh-h:first-child { margin-top: 2px; }
body.glyph-on #ghint { opacity: 0; }
.is-mobile #ghint { display: none !important; }

/* ── ghost teacher ──────────────────────────────────────────────
   the owner's recorded hand replayed as a separate being, made of
   the form's own flesh (depth clips, bone-to-amber palette on the
   canvas side). The mock sheet obeys the site's chromatic law: UI
   is strictly monochrome — ink at whispers, color lives only in
   the flesh. Above the chapter sheet (35), below the visitor's own
   cursor (80). Dormant until wired. */

#ghost-stage {
  position: fixed; inset: 0; z-index: 55; pointer-events: none;
  opacity: 0; transition: opacity 0.7s;
}
/* while the being teaches, the real chapter steps into shadow — the
   mock skeleton must read ABOVE the content, not tangled with it
   (the owner, 12.07); the form dims the same way (setTeachDim) */
#space { transition: opacity 0.7s; }
body.teaching #space { opacity: 0.12; }
#ghost-stage.on { opacity: 1; }
/* the outro leaves twice as fast as the intro came (the owner's timing) */
#ghost-stage.fast { transition: opacity 0.35s; }
#ghost-hand { position: absolute; inset: 0; width: 100%; height: 100%; }

/* the mock sheet: a chapter's see-through skeleton — kicker, title,
   text lines, a photo strip. Enough body to demonstrate scroll and
   the fist on, honest enough to never be read as real content. */
#ghost-mock {
  position: absolute; top: 50%; left: 8vw; width: min(560px, 44vw);
  transform: translateY(-50%);
  opacity: 0; transition: opacity 0.7s;
}
#ghost-stage.mock-on #ghost-mock { opacity: 1; }
/* the mirrored scroll lesson for right-side chapters: the skeleton
   stands right, and those chapters carry no photo strip */
#ghost-stage.mock-right #ghost-mock { left: auto; right: 8vw; }
#ghost-stage.mock-right #ghost-mock .gm-strip { display: none; }
#ghost-mock i { display: block; border-radius: 2px; }
#ghost-mock .gm-kicker {
  width: 92px; height: 9px; margin-bottom: 24px;
  background: rgba(170, 191, 224, 0.22);
}
#ghost-mock .gm-title {
  width: 72%; height: 28px; margin-bottom: 30px;
  background: rgba(170, 191, 224, 0.15);
}
#ghost-mock .gm-line {
  width: 100%; height: 11px; margin-bottom: 15px;
  background: rgba(170, 191, 224, 0.08);
}
#ghost-mock .gm-line.w60 { width: 60%; }
#ghost-mock .gm-line.w80 { width: 80%; }
#ghost-mock .gm-strip { display: flex; gap: 14px; margin: 28px 0; }
#ghost-mock .gm-strip i {
  flex: 1; aspect-ratio: 4 / 3;
  background: rgba(170, 191, 224, 0.05);
  border: 1px solid rgba(170, 191, 224, 0.16);
}

/* the gallery act: the fist takes a photo and it goes FULLSCREEN —
   exactly the site's own behavior — riding under the hand; the held
   fist carries the stack, the opening palm collapses it back. The
   sheet's skeleton steps into shadow while the frame is up. The frame
   lives on the stage, not in the sheet column (a taken photo leaves
   its content line on the real site too). */
#ghost-mock > i, #ghost-mock .gm-strip { transition: opacity 0.45s; }
#ghost-stage.lb-on #ghost-mock > i,
#ghost-stage.lb-on #ghost-mock .gm-strip { opacity: 0.22; }
#ghost-stage .gm-lb {
  position: absolute; inset: 8vh 9vw;
  transform: scale(0.3);
  transform-origin: 26% 62%;   /* it grows out of the strip's corner */
  opacity: 0; overflow: hidden;
  background: rgba(10, 10, 13, 0.72);
  border: 1px solid rgba(170, 191, 224, 0.22);
  transition: opacity 0.4s, transform 0.55s cubic-bezier(0.22, 0.61, 0.36, 1);
  pointer-events: none;
}
#ghost-stage.lb-on .gm-lb {
  opacity: 1;
  transform: scale(1);
}
/* the stack REPLACES photos, like the site's own gallery — cells lie
   on top of each other and crossfade on each step of the carry; the
   swap is deliberately ~2× lazier than the real one. Placeholders
   differ in weight and caption so the replacement is visible. */
#ghost-stage .gm-film { position: absolute; inset: 0; }
#ghost-stage .gm-film i {
  position: absolute; inset: 0; opacity: 0;
  transition: opacity 0.5s;
  background: rgba(170, 191, 224, 0.07);
  border: 1px solid rgba(170, 191, 224, 0.18);
  border-radius: 2px;
}
#ghost-stage .gm-film i.cur { opacity: 1; }
#ghost-stage .gm-film i:nth-child(2) { background: rgba(170, 191, 224, 0.12); }
#ghost-stage .gm-film i:nth-child(3) { background: rgba(170, 191, 224, 0.04); }
#ghost-stage .gm-film i::after {
  content: ''; position: absolute; left: 26px; bottom: 22px; height: 8px;
  background: rgba(170, 191, 224, 0.22); border-radius: 2px;
}
#ghost-stage .gm-film i:nth-child(1)::after { width: 120px; }
#ghost-stage .gm-film i:nth-child(2)::after { width: 84px; }
#ghost-stage .gm-film i:nth-child(3)::after { width: 156px; }
.is-mobile #ghost-stage { display: none !important; }

/* ?zero — the photo booth: nothing but the particle form on stage.
   The vignette and grain stay: they are the fabric of the frame, not UI. */
body.zero .corner, body.zero #identity, body.zero #nodes, body.zero #ghint,
body.zero #cursor, body.zero #scroll-hint, body.zero #invite-s2,
body.zero #ghost-stage {
  display: none !important;
}
