/* ╔═══════════════════════════════════════════════════════════════════╗
   ║  SWEEPERCOM // THE DARKROOM — SHARED SHELL                        ║
   ║  Loaded by every page. Page-specific CSS loads after this.        ║
   ╠═══════════════════════════════════════════════════════════════════╣
   ║  ★ COLOR KEY ★ (find & replace a hex to retheme the whole site)   ║
   ║    #070406  void / page background                                ║
   ║    #130b0d  panel background                                      ║
   ║    #1c1013  recessed / inset background                           ║
   ║    #2e181c  borders, dividers                                     ║
   ║    #f0e6e4  primary text                                          ║
   ║    #9b7d7e  muted text                                            ║
   ║    #ff2d2d  accent — safelight red (glows, active states)         ║
   ║    #e0863c  secondary accent — amber (labels, highlights)         ║
   ║    #e2d8c8  photo paper                                           ║
   ║                                                                   ║
   ║  ★ WHAT CHANGED COMING OFF JANITORAI ★                            ║
   ║    Everything in the old SECTION 1/2/10b/10c is GONE. Those       ║
   ║    rules existed to fight JanitorAI's own DOM — the .pp-* rail,   ║
   ║    the native card grid, the follow/options row, the filter       ║
   ║    modal. None of that markup exists here, so none of those       ║
   ║    rules do either. ~700 lines deleted, nothing lost.             ║
   ║                                                                   ║
   ║    Things that are now ALLOWED and are actually used:             ║
   ║      • url() in CSS          (JAI stripped it — textures were     ║
   ║                               forced to be <img> layers)          ║
   ║      • data-* attributes     (JAI stripped them — genres had to   ║
   ║                               be classes like .pg-rpg)            ║
   ║      • isolation             (JAI stripped it — needed the        ║
   ║                               z-index:0 workaround)               ║
   ║      • real JavaScript       (the lantern, see SECTION 2b)        ║
   ║      • target="_blank"       (JAI stripped it)                    ║
   ║      • multiple stylesheets and pages                             ║
   ╚═══════════════════════════════════════════════════════════════════╝ */

/* ══════════════ SECTION 0 — RESET / GLOBALS ══════════════ */
*, *::before, *::after { box-sizing: border-box; }

:root {
  --void:    #070406;
  --panel:   #130b0d;
  --inset:   #1c1013;
  --line:    #2e181c;
  --text:    #f0e6e4;
  --muted:   #9b7d7e;
  --red:     #ff2d2d;
  --amber:   #e0863c;
  --paper:   #e2d8c8;
  --ink:     #33261f;

  --mono:  "Courier Prime", "Courier New", monospace;
  --slab:  "Special Elite", "Courier New", monospace;
  --hand:  "Caveat Brush", "Segoe Script", cursive;

  /* THE LANTERN. js/lantern.js writes these every frame.
     Defaults are the no-JS state: radius 0 means the mask never opens,
     so the room just sits at its normal gloom. Nothing breaks. */
  --lx: 50%;
  --ly: 40vh;
  --lr: 0px;
}

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--void);
  color: var(--text);
  font-family: var(--mono);
  line-height: 1.6;
  overflow-x: hidden;
  /* a focusing loupe, not an arrow */
  cursor: crosshair;
}
a, button, summary { cursor: pointer; }

img { max-width: 100%; }
p { margin: 0 0 0.9em; }

::selection { background: var(--red); color: var(--void); }
::-webkit-scrollbar { width: 9px; background: var(--void); }
::-webkit-scrollbar-track { background: var(--void); border-left: 1px solid var(--line); }
::-webkit-scrollbar-thumb { background: var(--red); border: 1px solid var(--void); }
::-webkit-scrollbar-thumb:hover { background: var(--amber); }

/* keyboard users must be able to see where they are, even in the dark */
:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 2px;
}

/* ══════════════ SECTION 1 — THE DOOR RAIL ══════════════
   The old build spent 120 lines restyling JanitorAI's header into
   "mounted darkroom hardware". Same look, but now it is our own
   markup and there is nothing to fight — no !important anywhere.
   ══════════════════════════════════════════════════════════════ */
.rail {
  position: sticky; top: 0; z-index: 70;
  background: linear-gradient(180deg, #2a1c1a 0%, #1a1012 42%, #140c0e 60%, #0b0607 100%);
  border-bottom: 1px solid #000;
  box-shadow:
    inset 0 1px 0 rgba(226,216,200,0.10),
    0 3px 14px rgba(0,0,0,0.75),
    0 0 26px rgba(255,45,45,0.07);
}
/* shelf edge — the lip of the rail catching the safelight */
.rail::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: -3px; height: 3px;
  background: linear-gradient(180deg, rgba(255,45,45,0.30), rgba(255,45,45,0));
  pointer-events: none;
}
/* the red indicator bulb, on the SAME timeline as the safelight so the
   whole room shares one electrical supply */
.rail::after {
  content: ""; position: absolute; right: 14px; top: 50%; margin-top: -3px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--red);
  box-shadow: 0 0 8px rgba(255,45,45,0.9), 0 0 16px rgba(255,45,45,0.45);
  pointer-events: none;
  animation: dk-boot-lamp 2.2s linear both, dk-lamp 11s 2.2s infinite;
}
.rail-in {
  max-width: 1200px; margin: 0 auto;
  padding: 0 40px 0 24px;
  min-height: 46px;
  display: flex; align-items: center; gap: 18px;
  position: relative;
}
/* mounting screws at each end of the rail */
.rail-in::before, .rail-in::after {
  content: ""; position: absolute; top: 50%; margin-top: -4px;
  width: 8px; height: 8px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle at 34% 30%, #8a7d70, #453b34 60%, #241a16 100%);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.7), 0 1px 1px rgba(226,216,200,0.10);
}
.rail-in::before { left: 8px; }
.rail-in::after  { right: 30px; }

.rail-brand {
  font-family: var(--slab);
  font-size: 0.78rem; letter-spacing: 5px; text-transform: uppercase;
  color: #8d7470; text-decoration: none;
  text-shadow: 0 1px 0 rgba(0,0,0,0.9), 0 -1px 0 rgba(226,216,200,0.06);
  margin-left: 14px;
  white-space: nowrap;
  transition: color 0.25s ease;
}
.rail-brand:hover { color: var(--red); }

.rail-nav { display: flex; gap: 4px; margin-left: auto; flex-wrap: wrap; }
.rail-nav a {
  padding: 7px 15px;
  background: linear-gradient(180deg, #2e1f1c, #180e10);
  border: 1px solid #3a2620;
  border-radius: 2px;
  color: #c9b3ae; text-decoration: none;
  font-family: var(--mono);
  font-size: 0.62rem; font-weight: 700;
  letter-spacing: 3px; text-transform: uppercase;
  box-shadow: inset 0 1px 0 rgba(226,216,200,0.12), 0 2px 0 #0a0506, 0 3px 6px rgba(0,0,0,0.6);
  transition: 0.12s ease;
}
.rail-nav a:hover {
  color: var(--red); border-color: var(--red);
  box-shadow: inset 0 1px 0 rgba(226,216,200,0.12), 0 2px 0 #0a0506, 0 0 16px rgba(255,45,45,0.35);
}
.rail-nav a:active { transform: translateY(2px); box-shadow: inset 0 2px 4px rgba(0,0,0,0.8); }
/* the room you are standing in */
.rail-nav a[aria-current="page"] {
  color: var(--void); background: var(--red); border-color: var(--red);
  box-shadow: 0 0 16px rgba(255,45,45,0.35);
}

/* ══════════════ SECTION 2 — LAYERS & THE GLOOM ══════════════
   LAYER BUDGET (do not reshuffle casually):
      -1  .dk-wall     tile wall, fixed behind everything
       —  page content, normal flow, NO z-index (see note)
      59  .dk-lampglow safelight bloom, page-anchored
      60  .dk-ambient  the gloom + vignette. The lantern cuts a hole in THIS.
      61  .dk-lantern  warm pool of light at the pointer
      62  .dk-grain    film grain
      63  .dk-dust     drifting motes
      64  .dk-blackout the boot animation
      65  .dk-safelight the fixture itself — the one real light in the room
      70  .rail        always reachable, always above every light effect

   ⚠ Page content deliberately has NO z-index and NO isolation. If you
     give the content wrapper a stacking context, the z-60+ overlays get
     trapped relative to it and the whole lighting rig stops working.
     Overlays are all pointer-events:none, so they never eat a click.
   ══════════════════════════════════════════════════════════════ */
/* The whole page body below the rail. It is position:relative so the
   page-anchored things (the lamp fixture, the safelight bloom, the tape
   strips) have something to measure against — and NOTHING else. Do not
   give it a z-index or an isolation; that would trap every overlay
   below. See the layer budget above. */
.page { position: relative; }

.dk-wall, .dk-grain, .dk-dust, .dk-ambient, .dk-lantern, .dk-blackout {
  position: fixed; inset: 0;
  pointer-events: none;
}
.dk-wall, .dk-grain, .dk-dust { width: 100%; height: 100%; object-fit: cover; }

.dk-wall  { z-index: -1; opacity: 0.22; }
.dk-grain { z-index: 62; opacity: 0.13; mix-blend-mode: overlay; }
.dk-dust  { z-index: 63; opacity: 0.16; object-position: 46% 46%; animation: dk-dustdrift 40s ease-in-out infinite alternate; }
@keyframes dk-dustdrift { from { object-position: 44% 44%; } to { object-position: 56% 56%; } }

/* ---- the permanent gloom, with a hole cut where the lantern is ---- */
.dk-ambient {
  z-index: 60;
  background:
    linear-gradient(90deg, rgba(0,0,0,0.5) 0%, rgba(0,0,0,0) 8%, rgba(0,0,0,0) 92%, rgba(0,0,0,0.5) 100%),
    radial-gradient(ellipse 900px 700px at 50% 30%, rgba(0,0,0,0) 0%, rgba(0,0,0,0.38) 60%, rgba(0,0,0,0.56) 100%);
  opacity: 0.62;
  -webkit-mask-image: radial-gradient(circle var(--lr) at var(--lx) var(--ly), transparent 0%, rgba(0,0,0,0.55) 45%, #000 100%);
          mask-image: radial-gradient(circle var(--lr) at var(--lx) var(--ly), transparent 0%, rgba(0,0,0,0.55) 45%, #000 100%);
  animation: dk-amb 11s 2.2s infinite;
}

/* ══════════════ SECTION 2b — THE LANTERN ══════════════
   The old file has a long comment explaining why a cursor-following
   lamp was IMPOSSIBLE on JanitorAI:

     "CSS cannot read the pointer's coordinates. There is no shipped
      --mouse-x. That needs JS, and JanitorAI strips JS."
     "...a mesh of hover cells would eat clicks on the prints, the
      filters, the monitor and the Options button. Not worth it."

   Both of those are dead constraints now. js/lantern.js writes --lx,
   --ly and --lr onto :root every frame, the gloom above is masked with
   them, and this layer paints the warm pool. One rAF loop, ~40 lines,
   no hit-testing, nothing swallows a click.

   The inverted "whatever you point at lifts out of the dark" hover
   trick from the old SECTION 7b is KEPT — it now reinforces the real
   lantern instead of standing in for it.
   ══════════════════════════════════════════════════════════════ */
.dk-lantern {
  z-index: 61;
  mix-blend-mode: screen;
  background: radial-gradient(
    circle calc(var(--lr) * 0.92) at var(--lx) var(--ly),
    rgba(255,132,86,0.30) 0%,
    rgba(255,70,50,0.16) 34%,
    rgba(150,26,22,0.06) 62%,
    rgba(0,0,0,0) 78%);
  transition: opacity 0.5s ease;
}
/* while the pointer is off the page the lamp is lowered, not killed */
html.lantern-away .dk-lantern { opacity: 0.35; }

/* ---- the safelight bloom over the masthead (page-anchored) ---- */
.dk-lampglow {
  position: absolute; left: 0; right: 0; top: 0; height: 620px;
  z-index: 59; pointer-events: none; mix-blend-mode: screen;
  background: radial-gradient(ellipse 520px 420px at 50% 96px,
    rgba(255,60,45,0.42) 0%, rgba(255,45,45,0.16) 34%,
    rgba(140,20,20,0.05) 58%, rgba(0,0,0,0) 72%);
  opacity: 0.85;
  animation: dk-boot-lamp 2.2s linear both, dk-lamp 11s 2.2s infinite;
}

/* ══════════════ SECTION 3 — BOOT + FLICKER ══════════════
   The room starts black except the lamp, stutters twice, then settles.
   Over in 2.2s, then the lamp flickers every 11s forever.

   ⚠ Boot and idle are ONE declaration each:
       animation: <boot> 2.2s both, <idle> 11s 2.2s infinite;
     The idle has a 2.2s delay and NO fill, so it contributes nothing
     until boot finishes; then, being later in the list, it wins the
     opacity. Keep boot's 100% equal to idle's 0% or the handoff jumps.
   ══════════════════════════════════════════════════════════════ */
.dk-blackout {
  z-index: 64;
  background: radial-gradient(ellipse 460px 380px at 50% 84px,
    rgba(0,0,0,0) 0%, rgba(0,0,0,0.55) 38%, rgba(0,0,0,0.97) 68%, #000 100%);
  animation: dk-boot 2.2s linear both;
}
@keyframes dk-boot {
  0%,14%   { opacity: 1; }
  16%      { opacity: 0.15; }
  19%,38%  { opacity: 1; }
  40%      { opacity: 0.10; }
  44%      { opacity: 0.95; }
  58%      { opacity: 1; }
  62%      { opacity: 0.08; }
  66%      { opacity: 0.50; }
  70%      { opacity: 0.05; }
  100%     { opacity: 0; }
}
@keyframes dk-boot-lamp {
  0%,14%   { opacity: 0.05; }
  16%      { opacity: 0.90; }
  19%,38%  { opacity: 0.05; }
  40%      { opacity: 1; }
  44%      { opacity: 0.10; }
  58%      { opacity: 0.05; }
  62%      { opacity: 1; }
  66%      { opacity: 0.55; }
  70%      { opacity: 1; }
  100%     { opacity: 0.85; }
}
@keyframes dk-amb {
  0%,84%,100% { opacity: 0.62; }
  85%         { opacity: 0.90; }
  86%         { opacity: 0.62; }
  87.5%       { opacity: 0.96; }
  88.5%       { opacity: 0.65; }
  89.5%       { opacity: 0.62; }
}
@keyframes dk-lamp {
  0%,84%,100% { opacity: 0.85; }
  85%         { opacity: 0.18; }
  86%         { opacity: 0.85; }
  87.5%       { opacity: 0.10; }
  88.5%       { opacity: 0.80; }
  89.5%       { opacity: 0.85; }
}

/* flicker is the whole point, but never at the cost of someone's health */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .dk-blackout  { animation: none; opacity: 0; }
  .dk-ambient   { animation: none; opacity: 0.62; }
  .dk-lampglow  { animation: none; opacity: 0.85; }
  .rail::after  { animation: none; opacity: 1; }
  .dk-dust      { animation: none; }
  .dk-safelight .lamp-on { animation: none; opacity: 0.9; }
}

/* ══════════════ SECTION 4 — THE FIXTURE ══════════════
   The lamp hangs at z65, ABOVE every darkness layer, because it is the
   one thing you should always see in a black room. It reads as "off"
   at rest because .lamp-on is nearly transparent, not because it is
   hidden. Lit and unlit assets are pixel-aligned (both 800x1000, same
   alpha bbox) so they crossfade in place with no jump.
   ══════════════════════════════════════════════════════════════ */
.dk-safelight {
  position: absolute; top: -18px; left: 50%;
  width: 150px; margin-left: -75px;
  z-index: 65; pointer-events: none;
}
.dk-safelight img { width: 100%; display: block; }
.dk-safelight .lamp-off { filter: brightness(0.42) saturate(0.55); }
.dk-safelight .lamp-on {
  position: absolute; inset: 0; opacity: 0.85;
  animation: dk-boot-lamp 2.2s linear both, dk-lamp 11s 2.2s infinite;
}

/* ══════════════ SECTION 5 — MASTHEAD ══════════════ */
.masthead {
  position: relative;
  width: 100%;
  /* ⚠ CLEARS THE LAMP. The fixture hangs from .page top:-18px and is
     ~187px tall at this width, so anything above ~190px lands behind
     the shade. If you resize .dk-safelight, resize this to match. */
  padding: 190px 24px 46px;
  text-align: center;
  background: radial-gradient(ellipse 760px 520px at 50% 150px,
    rgba(255,45,45,0.26), rgba(255,45,45,0.07) 42%, transparent 70%);
  border-bottom: 1px solid var(--line);
  overflow: hidden;
}
.masthead.tall { padding-top: 210px; }
/* scanlines */
.masthead::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: repeating-linear-gradient(0deg, rgba(255,45,45,0.04) 0 1px, transparent 1px 3px);
  animation: gm-scan 12s linear infinite;
}
@keyframes gm-scan { 0% { background-position: 0 0; } 100% { background-position: 0 120px; } }
/* film-leader sprocket holes down both edges */
.masthead::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0.22;
  background-image:
    repeating-linear-gradient(180deg, transparent 0 14px, rgba(226,216,200,0.5) 14px 30px, transparent 30px 44px),
    repeating-linear-gradient(180deg, transparent 0 14px, rgba(226,216,200,0.5) 14px 30px, transparent 30px 44px);
  background-size: 13px 44px, 13px 44px;
  background-position: left top, right top;
  background-repeat: repeat-y, repeat-y;
}
.eyebrow {
  font-family: var(--slab);
  font-size: 0.75rem; letter-spacing: 8px; text-transform: uppercase;
  color: var(--amber); margin-bottom: 10px;
}
.masthead h1 {
  font-family: var(--slab); font-weight: 700;
  font-size: clamp(2.6rem, 7vw, 5.5rem);
  letter-spacing: 5px; text-transform: uppercase;
  color: var(--text);
  text-shadow: 0 0 30px rgba(255,45,45,0.35);
  margin: 0; line-height: 1;
  animation: gm-title-in 1s ease both;
}
@keyframes gm-title-in {
  0%   { opacity: 0; letter-spacing: 18px; filter: blur(6px); }
  100% { opacity: 1; letter-spacing: 5px; filter: blur(0); }
}
.subtitle {
  color: var(--muted); letter-spacing: 3px; margin-top: 14px;
  font-size: 0.85rem; text-transform: uppercase;
}
.subtitle b { color: var(--red); font-weight: 400; }
.masthead-menu { display: flex; justify-content: center; gap: 4px; margin-top: 34px; flex-wrap: wrap; }
.masthead-menu a {
  padding: 10px 26px;
  border: 1px solid var(--line);
  color: var(--muted);
  font-family: var(--slab); font-weight: 600;
  letter-spacing: 2px; text-transform: uppercase;
  text-decoration: none; font-size: 0.85rem;
  transition: 0.25s ease;
}
.masthead-menu a::before { content: "▸ "; color: var(--red); opacity: 0; transition: 0.25s ease; }
.masthead-menu a:hover { color: var(--red); border-color: var(--red); box-shadow: 0 0 14px rgba(255,45,45,0.25); }
.masthead-menu a:hover::before { opacity: 1; }

/* ══════════════ SECTION 6 — SHARED FURNITURE ══════════════ */
.shell { width: 100%; max-width: 1200px; margin: 0 auto; padding: 0 24px; }

.zone { width: 100%; padding: 56px 0 24px; position: relative; }
.zone + .zone { border-top: 1px solid var(--line); }

.zone-head { text-align: center; margin-bottom: 30px; }
.zone-head h2 {
  font-family: var(--slab); font-size: 1.7rem;
  letter-spacing: 3px; text-transform: uppercase;
  color: var(--text); margin: 0;
  text-shadow: 0 0 24px rgba(255,45,45,0.3);
}
.zone-head h2::before, .zone-head h2::after { content: " ✦ "; color: var(--red); }
.zone-head small {
  display: block; color: var(--amber);
  letter-spacing: 5px; font-size: 0.64rem; text-transform: uppercase;
  margin-top: 8px; font-family: var(--mono);
}

.hint {
  text-align: center; margin-top: 12px;
  font-family: var(--mono); font-size: 0.56rem;
  letter-spacing: 3px; text-transform: uppercase; color: #6b544a;
}

.credit {
  text-align: center; padding: 46px 24px 40px;
  font-family: var(--mono); font-size: 0.58rem;
  letter-spacing: 4px; text-transform: uppercase; color: #6b544a;
  border-top: 1px solid var(--line); margin-top: 40px;
}
.credit a { color: #8d7470; text-decoration: none; }
.credit a:hover { color: var(--red); }

/* the button that appears anywhere something is openable */
.chem-link, .btn {
  display: inline-block; padding: 11px 26px;
  border: 1px solid var(--red); color: var(--red);
  text-decoration: none; font-family: var(--mono);
  letter-spacing: 3px; text-transform: uppercase;
  font-size: 0.76rem; font-weight: 700;
  transition: 0.25s ease;
}
.chem-link:hover, .btn:hover {
  background: var(--red); color: #0a0506;
  box-shadow: 0 0 24px rgba(255,45,45,0.5);
}

/* ---- skip link: the way out of the dark for keyboard users ---- */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--red); color: var(--void);
  padding: 10px 18px; font-family: var(--mono);
  font-weight: 700; letter-spacing: 2px; text-transform: uppercase;
}
.skip:focus { left: 0; }

/* ══════════════ SECTION 7 — THE TAPE ══════════════
   The contact sheet, strung across the room like crime-scene tape:
   three strips of film at angles, zig-zagging down the page behind
   the content.

   LAYERING: strips sit at z-index -1 — above the wall, behind
   everything you read. Absolutely positioned inside .tape-field so
   they scroll with the page rather than hovering over the viewport.

   MOTION IS SPLIT ACROSS TWO ELEMENTS ON PURPOSE:
     .reel-run   plain, always-running loop. Never remove it.
     .reel-shift scroll-driven nudge layered on top.
   If a browser has no scroll timelines, or the timeline is inactive,
   the shift contributes nothing and the tape KEEPS MOVING on the run
   loop. Merging them would risk a frozen strip.

   SEAMLESS-LOOP RULE: each strip holds 2 identical runs and slides by
   exactly one run (-50%). For the join to hide, ONE run must be at
   least as wide as the strip. Strip is 136% of page width; 20 frames
   at ~155px pitch covers it. Drop frames and a bare gap appears.
   ══════════════════════════════════════════════════════════════ */
/* ⚠ THE FIELD STARTS BELOW THE MASTHEAD, ON PURPOSE.
   On JanitorAI the strips spanned the entire profile and the top one
   ran straight through the title — it survived only because the gloom
   there was heavy enough to bury it. With the lighting rebuilt, a
   strip of bright character art across the wordmark just reads as a
   mistake. --tape-top is set to clear the masthead; the strips then
   spread over the content below it, where they belong.
   Keep this in sync with .masthead padding if you change it. */
.tape-field {
  position: absolute; left: 0; right: 0;
  top: var(--tape-top, 540px); bottom: 0;
  z-index: -1; overflow: hidden; pointer-events: none;
}
.reel-strip {
  position: absolute; left: -18%; width: 136%; height: 176px; overflow: hidden;
  background: linear-gradient(180deg, #080405 0%, #170d10 16%, #170d10 84%, #080405 100%);
  border-top: 1px solid #2c1b17; border-bottom: 1px solid #2c1b17;
  box-shadow: 0 14px 34px rgba(0,0,0,0.62), inset 0 1px 0 rgba(226,216,200,0.10), 0 0 26px rgba(255,45,45,0.12);
  /* ⚠ VISIBILITY BUDGET — RETUNED FOR THIS BUILD.
     On JanitorAI the gloom was a flat, heavy layer that ate about a
     third of the tape, so the strips were pushed to 0.78 x 0.90 just
     to stay visible. The lantern punches a hole in that gloom, so the
     SAME numbers here made the tape brighter than the headings it sits
     behind. Retuned down: it is texture, not content. If you raise
     these, check the section headings still read over the strips. */
  opacity: 0.6;
}
/* perforations along both long edges */
.reel-strip::before, .reel-strip::after {
  content: ""; position: absolute; left: -4%; right: -4%; height: 11px; z-index: 3; pointer-events: none;
  background: repeating-linear-gradient(90deg,
    transparent 0 11px, rgba(226,216,200,0.15) 11px 23px, transparent 23px 34px);
}
.reel-strip::before { top: 4px; }
.reel-strip::after  { bottom: 4px; }
.reel-shift { height: 100%; will-change: transform; }
.reel-run {
  display: flex; height: 100%; width: max-content; gap: 5px; padding: 13px 0;
  will-change: transform;
}
.reel-frame {
  height: 100%; width: auto; aspect-ratio: 1; object-fit: cover; display: block;
  border: 1px solid #241713;
  filter: saturate(0.5) brightness(0.5) contrast(1.05);
  transition: filter 0.3s ease, transform 0.3s ease;
  pointer-events: auto;
}
.reel-frame:hover {
  filter: saturate(1.05) brightness(1.12) contrast(1.02);
  transform: scale(1.06);
  box-shadow: 0 0 26px rgba(255,116,66,0.4);
}
/* the zig-zag: alternating angles down the page */
.reel-strip.r1 { top: 13%; transform: rotate(-4.2deg); }
.reel-strip.r2 { top: 47%; transform: rotate(3.6deg); }
.reel-strip.r3 { top: 79%; transform: rotate(-3.2deg); }
@keyframes dk-reel-l { from { transform: translateX(0); }    to { transform: translateX(-50%); } }
@keyframes dk-reel-r { from { transform: translateX(-50%); } to { transform: translateX(0); } }
.r1 .reel-run, .r3 .reel-run { animation: dk-reel-l 190s linear infinite; }
.r2 .reel-run { animation: dk-reel-r 210s linear infinite; }
@keyframes dk-reel-sl { from { transform: translateX(5%); }  to { transform: translateX(-9%); } }
@keyframes dk-reel-sr { from { transform: translateX(-9%); } to { transform: translateX(5%); } }
@supports (animation-timeline: scroll()) {
  .reel-shift {
    animation-timeline: scroll(root block);
    animation-duration: auto;
    animation-timing-function: linear;
    animation-fill-mode: both;
  }
  .r1 .reel-shift, .r3 .reel-shift { animation-name: dk-reel-sl; }
  .r2 .reel-shift { animation-name: dk-reel-sr; }
}
@media (prefers-reduced-motion: reduce) {
  .reel-run { animation: none; }
  .reel-shift { animation: none; }
}

/* ══════════════ SECTION 8 — SCENE PROPS ══════════════ */
.prop-enlarger {
  position: absolute; right: 0; bottom: 54px; width: 168px;
  z-index: 0; opacity: 0.42; pointer-events: none;
  transition: opacity 0.5s ease, filter 0.5s ease;
}
.prop-enlarger img { width: 100%; display: block; filter: brightness(0.55) saturate(0.55); }
.prop-enlarger::after {
  content: ""; position: absolute; left: -118px; top: 34%;
  width: 250px; height: 300px;
  background: linear-gradient(198deg, rgba(255,120,90,0.42), transparent 72%);
  clip-path: polygon(54% 0, 66% 0, 100% 100%, 0 100%);
  pointer-events: none;
}
.prop-tongs {
  position: absolute; left: -26px; bottom: 40px; width: 150px;
  z-index: 0; opacity: 0.4; pointer-events: none;
  transform: rotate(-14deg); filter: brightness(0.65);
}
.prop-loupe {
  position: absolute; left: 96px; bottom: 12px; width: 62px;
  z-index: 0; opacity: 0.45; pointer-events: none; filter: brightness(0.7);
}

/* ══════════════ SECTION 9 — THE ATTENTION POOL ══════════════
   Held over from the old build's SECTION 7b. Whatever you point AT
   lifts out of the gloom and throws a warm halo, as though you were
   holding the lamp up to it. With the real lantern now running, the
   two read as one light source.
   ══════════════════════════════════════════════════════════════ */
.peg, .lore-print, .lore-note, .bottle, .crt, .easel-shot,
.reel-frame, .dk-safelight, .chem-link, .line-arrow {
  transition: filter 0.4s ease, box-shadow 0.4s ease, opacity 0.4s ease, transform 0.4s ease;
}
.peg:hover, .bottle:hover, .crt:hover, .easel-shot:hover,
.lore-flip:hover .lore-print, .lore-flip:hover .lore-note {
  box-shadow: 0 0 70px 16px rgba(255,116,66,0.20), 0 1em 2em rgba(0,0,0,0.75);
}
.bottle:hover, .crt:hover { filter: brightness(1.38) saturate(1.12); }
.dk-safelight:hover .lamp-on { opacity: 1; }
/* the room leans toward whatever you are looking at */
.line:hover .prop-enlarger { opacity: 0.62; filter: brightness(0.85); }

/* ══════════════ SECTION 10 — MOBILE ══════════════ */
@media screen and (max-width: 900px) {
  .rail-in { padding: 6px 34px 6px 20px; flex-wrap: wrap; gap: 8px; }
  .rail-brand { margin-left: 10px; font-size: 0.68rem; letter-spacing: 3px; }
  .rail-nav { margin-left: auto; gap: 3px; }
  .rail-nav a { padding: 6px 10px; font-size: 0.56rem; letter-spacing: 2px; }
  /* lamp is 96px wide here, so ~120px tall — less to clear */
  .masthead { padding: 140px 16px 40px; }
  .masthead.tall { padding-top: 158px; }
  .masthead h1 { letter-spacing: 2px; }
  .masthead-menu a { padding: 9px 16px; font-size: 0.75rem; }
  .reel-strip { height: 104px; }
  .reel-strip.r1 { top: 10%; }
  .reel-strip.r2 { top: 45%; }
  .reel-strip.r3 { top: 80%; }
  /* shorter masthead up here, so the tape can start sooner */
  :root { --tape-top: 420px; }
  .shell { padding: 0 16px; }
}
@media screen and (max-width: 520px) {
  :root { --tape-top: 340px; }
  .masthead h1 { font-size: 2.1rem; }
  .zone-head h2 { font-size: 1.35rem; }
  .dk-safelight { width: 96px; margin-left: -48px; }
  .prop-enlarger, .prop-tongs, .prop-loupe { display: none; }
}

/* ══════════════ SECTION 11 — TOUCH / COARSE POINTERS ══════════════
   There is no cursor to follow on a phone, so the lantern would just
   sit wherever the last tap landed. lantern.js refuses to start on a
   coarse pointer; this lifts the gloom a little to compensate for the
   light that is no longer travelling around.
   ══════════════════════════════════════════════════════════════ */
@media (hover: none), (pointer: coarse) {
  body { cursor: auto; }
  .dk-ambient { opacity: 0.46; }
}
