/* =========================================================
   adventure.css — VioLev "Adventure" section styles (room codename: Labs)

   THE WORKBENCH ROOM (Session 4 build).
   Single-screen fit-to-viewport (same shell as the home hero), with the
   flashlight reveal over the inked workbench plate:
     room opens near-black -> warm lamp-spill from centre-top -> quick fade
     -> ~1.5s black -> a focused beam eases in and follows the pointer
     (finger-drag on touch). The pool shows the warm wood at true colour;
     near-pitch everywhere else. Artifacts (later) bloom violet only inside
     the lit pool.

   PROGRESSIVE ENHANCEMENT: the dark game lives under html.js (set in <head>
   via $head_extra, so no flash). No JS  -> lit static room + links. Reduced
   motion -> lit static room + links (the beam game is skipped). The link
   strip is always real and reachable — the guaranteed way in.

   NOTE: the fit-to-viewport shell rules are duplicated from the home hero for
   now; they fold into a shared screen.css when the H/J/A roll locks that
   decision. The flashlight mechanic stays Adventure-only.
   ========================================================= */

/* ---- fit-to-viewport shell: one screen, footer pinned, no scroll by FIT ---- */
body { height: 100vh; height: 100dvh; display: flex; flex-direction: column; }
main { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.site-footer { flex: 0 0 auto; }

/* ---- the room: fills main; the only overflow:hidden is the dark boundary ---- */
.room {
  position: relative; flex: 1 1 auto; min-height: 0;
  overflow: hidden;
  background: var(--abyss);
  --x: 50%; --y: 50%;     /* beam centre, set live by JS */
  --r: 26vmin;            /* BEAM radius fallback (JS sizes from room height) */
  --rb: 38vmin;           /* soft violet edge ring fallback */
}

/* every layer is the same inked plate (path set inline via --plate, $base-safe) */
.plate { position: absolute; inset: 0; background: var(--plate) center/cover no-repeat; }

/* ---- DEFAULT (no JS / fallback): the room is simply shown lit + static ---- */
.plate-dark { filter: brightness(1) saturate(1); }
.plate-lit, .plate-arrival, .room-bloom { display: none; }

/* ---- the guaranteed way in: real links beneath the game (keyboard / SR /
        indexing). Dim in the dark game; clearer in the lit fallback. ---- */
.bench-doors {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 26px;
  padding: 14px 20px;
  font-family: var(--mono); font-size: .66rem; letter-spacing: .22em; text-transform: uppercase;
}
.bench-doors a {
  color: var(--haze); opacity: .82; text-decoration: none; cursor: pointer;
  transition: opacity var(--transition-fast), color var(--transition-fast), text-shadow var(--transition-fast);
}
.bench-doors a:hover, .bench-doors a:focus-visible {
  opacity: 1; color: var(--violet-bright); text-shadow: var(--glow-violet-soft);
}
.bench-doors a:focus-visible { outline: none; text-decoration: underline; text-underline-offset: 4px; }

/* ===========================================================
   html.js — JS present + motion welcome: the dark flashlight room
   =========================================================== */
html.js .room { cursor: none; touch-action: none; }   /* the beam IS the cursor; drag drives it */

/* resting room: near pitch black (~3% light) */
html.js .plate-dark { filter: brightness(.03) saturate(.45); }

/* arrival: bench lifted to barely-visible, lit from the unseen lamp above
   centre-top; opacity animated by JS */
/* arrival "lamp on": the whole room lifts to warm, holds, then fades to dark.
   >>> LIGHT INTENSITY DIAL <<< is the brightness() below — 1 = the plate's true
   paint, higher = a brighter lamp. Opacity is driven by the @keyframes (not JS),
   so this dial now actually shows on screen. */
html.js .plate-arrival {
  display: block;
  filter: brightness(1.2) saturate(.9);
  -webkit-mask-image: radial-gradient(160% 150% at 50% 30%, #000 0%, #000 55%, transparent 100%);
          mask-image: radial-gradient(160% 150% at 50% 30%, #000 0%, #000 55%, transparent 100%);
  opacity: 0;
}
html.js .room.lamp .plate-arrival { animation: lamp-arrival 3900ms ease forwards; }
@keyframes lamp-arrival {
  0%   { opacity: 0; }
  6%   { opacity: 1; }   /* ~240ms: lamp on */
  76%  { opacity: 1; }   /* hold lit ~3s */
  94%  { opacity: 0; }   /* ~700ms: fade to dark */
  100% { opacity: 0; }
}

/* the flashlight: full warm plate revealed only inside the cursor pool;
   mostly-focused core then a soft feather = slight bloom at the edge */
html.js .plate-lit {
  display: block;
  filter: brightness(1.05) saturate(1.06);
  -webkit-mask-image: radial-gradient(circle var(--r) at var(--x) var(--y),
     #000 0%, #000 46%, rgba(0,0,0,.30) 74%, transparent 100%);
          mask-image: radial-gradient(circle var(--r) at var(--x) var(--y),
     #000 0%, #000 46%, rgba(0,0,0,.30) 74%, transparent 100%);
  opacity: 0; transition: opacity .6s ease;
}
html.js .room.armed .plate-lit { opacity: 1; }

/* a whisper of brand violet at the beam's soft edge (the pool itself stays warm) */
html.js .room-bloom {
  display: block; position: absolute; inset: 0; pointer-events: none;
  opacity: 0; transition: opacity .6s ease; mix-blend-mode: screen;
  background: radial-gradient(circle var(--rb) at var(--x) var(--y),
     rgba(168,123,255,.10) 0%, rgba(139,92,255,.05) 45%, transparent 72%);
}
html.js .room.armed .room-bloom { opacity: 1; }

/* dark game: the links are invisible to the eye but stay focusable + in the DOM
   (keyboard / screen-reader / indexing). Mystery preserved; the floor preserved.
   A Tab keypress surfaces one; a mouse sweeping the dark never sees them. */
html.js .bench-doors a { opacity: 0; pointer-events: none; }
html.js .bench-doors a:focus-visible { opacity: 1; pointer-events: auto; }

/* ===========================================================
   BENCH OBJECTS — the 5 doors, laid on the plate, revealed by the beam.
   Fallback (no-JS / reduced-motion): shown static + clickable.
   Dark game: masked by the SAME beam gradient as .plate-lit, so an object
   only shows inside the pool; the hidden cursor keeps the beam centred on
   the pointer, so you click what you light.
   POSITION DIALS are on each .obj-* below: --ox/--oy = centre (% of room),
   --ow = width (% of room), --ar = aspect from the source art. Tune by watching.
   =========================================================== */
.objects { position: absolute; inset: 0; z-index: 2; }   /* over plates, under the text strip (z3) */
.obj {
  position: absolute; left: var(--ox); top: var(--oy);
  width: var(--ow); aspect-ratio: var(--ar, 1);
  transform: translate(-50%, -50%);
  background: var(--img) center/contain no-repeat;
  text-decoration: none; cursor: pointer;
  transition: filter var(--transition-fast), transform var(--transition-fast);
}
/* live objects answer the light: a soft violet lift on hover/focus */
a.obj:hover, a.obj:focus-visible {
  filter: drop-shadow(0 0 10px rgba(168,123,255,.55));
  transform: translate(-50%, -50%) scale(1.03); outline: none;
}
/* the dossiers door isn't wired yet — present but inert (no ghost link) */
.obj.is-inert { cursor: default; pointer-events: none; }

/* ---- POSITION DIALS (centre %, width %, aspect from the art) ---- */
.obj-map    { --ox: 15%; --oy: 20%; --ow: 25%; --ar: 1.60; }  /* wall, upper-left  -> locator         */
.obj-wanted { --ox: 92%; --oy: 13%; --ow: 13%; --ar: 0.87; }  /* wall, right       -> dossiers        */
.obj-laptop { --ox: 33%; --oy: 43%; --ow: 22%; --ar: 1.29; }  /* bench top         -> console         */
.obj-comic  { --ox: 60%; --oy: 35%; --ow: 8%; --ar: 0.75; }  /* bench, right       -> cong-inc        */
.obj-clip   { --ox: 80%; --oy: 50%; --ow: 10%; --ar: 0.77; }  /* foreground, left  -> forms           */

/* ---- dark game: objects revealed only inside the beam; fade in once armed.
        pointer-events gate so an unrevealed object can't be blind-clicked. ---- */
html.js .objects {
  opacity: 0; pointer-events: none; transition: opacity .6s ease;
  -webkit-mask-image: radial-gradient(circle var(--r) at var(--x) var(--y),
     #000 0%, #000 46%, rgba(0,0,0,.30) 74%, transparent 100%);
          mask-image: radial-gradient(circle var(--r) at var(--x) var(--y),
     #000 0%, #000 46%, rgba(0,0,0,.30) 74%, transparent 100%);
}
html.js .room.armed .objects { opacity: 1; pointer-events: auto; }
html.js .room.armed .obj.is-inert { pointer-events: none; }

/* ---- reduced motion: honor it literally — even with JS, no arrival, no beam.
        Room shown lit + static, links the way in. (JS also skips the sequence.) ---- */
@media (prefers-reduced-motion: reduce) {
  html.js .room { cursor: auto; }
  html.js .plate-dark { filter: brightness(1) saturate(1); }
  html.js .plate-lit, html.js .plate-arrival, html.js .room-bloom { display: none; }
  html.js .objects { -webkit-mask-image: none; mask-image: none; opacity: 1; pointer-events: auto; }
  html.js .bench-doors a { opacity: .82; }
}

/* ---- portrait gate (phones + tablets): rotate-to-landscape wall. Landscape-
        only by design, same as the home hero. Touch + portrait only. ---- */
.rotate-nag { display: none; }
@media (orientation: portrait) and (pointer: coarse) {
  .rotate-nag {
    display: flex; position: fixed; inset: 0; z-index: 9999;
    flex-direction: column; align-items: center; justify-content: center;
    gap: 18px; padding: 40px; text-align: center; background: var(--void);
  }
  .rotate-nag-title { font-family: var(--display); font-weight: 600; font-size: clamp(1.4rem, 7vw, 2rem); color: var(--mist); }
  .rotate-nag-sub  { font-family: var(--mono); font-size: .72rem; letter-spacing: .14em; text-transform: uppercase; color: var(--haze); max-width: 32ch; line-height: 1.7; }
}

/* sr-only: page structure for crawlers / screen readers without lighting the room */
.sr-only {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
