:root {
  --bg: #050208;
}

.piece-less-is-more * {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
}

/* The scrub range. Height is large relative to the viewport so that a full
   pass through all chapters corresponds to a comfortable amount of scroll
   travel. 1200vh, not the original 600vh: phase 2 ("Guess the Door") added
   a second half past the original ending, and LEGACY_END in script.js
   (5/11) was solved so that the *original* content still gets exactly the
   600vh-equivalent scroll range it was tuned and verified against
   (1200vh - 100vh viewport) * 5/11 = 500vh, matching the old track's own
   effective (600vh - 100vh) scroll range exactly -- see script.js's own
   note on LEGACY_END for why this matters (every hand-tuned margin and
   boost-window offset in phase 1 assumes this same scroll-pixel budget;
   changing it without also rescaling every one of those offsets would
   silently speed up or slow down all of phase 1's own pacing). Grown once
   already (from 1000vh) specifically to widen the gap between "Play,
   blind" arriving and the geometric reveal starting, after the first,
   narrower gap turned out easy to scroll past accidentally -- see
   CHG.tetraStart's own note. The piece now ends on a *new* resting frame
   -- the tetrahedron reveal's own closing card -- past that point. */
.piece-less-is-more .scroll-track {
  position: relative;
  height: 1200vh;
  background: var(--bg);
}

.piece-less-is-more .pinned {
  position: sticky;
  top: 0;
  height: 100vh;
  width: 100%;
  overflow: hidden;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
}

.piece-less-is-more #scene {
  display: block;
  width: 100%;
  height: 100%;
}

/* An invisible, precisely-positioned/sized circular hit target, placed
   and sized by script.js (layoutTetraGrabZone) to sit exactly over the
   tetrahedron reveal's own rendered shape once it's draggable --
   touch-action: none, permanently, on *this* element only, never on
   #scene itself.
   Three earlier approaches lived directly on #scene instead, each
   reverted after a real failure on an actual device:
   1. A static `touch-action: pan-y` on #scene -- real fingers are never
      perfectly axis-aligned, so a real "mostly sideways" drag kept
      getting swallowed into a native scroll.
   2. A direction-based axis lock in JS -- still unreliable; direction is
      an inherently noisy signal to infer intent from.
   3. Deciding intent by location, but still toggling *#scene's own*
      touch-action dynamically ("none" only while active) and hand-
      rolling a manual scroll replay (window.scrollBy) for every
      off-shape gesture, since native scrolling was switched off for the
      *entire* canvas, not just the shape -- workable, but the manual
      replay is a noticeably worse approximation of scrolling than the
      real thing (no momentum, no elastic bounce, 1:1 tracking only),
      and *still* fragile to real browsers occasionally mishandling a
      touch-action change on an in-progress touch, however carefully
      timed -- reported directly as heavy flicker trying to scroll back
      out of the tetrahedron card.
   Splitting the shape's own hit-region out as a genuinely separate DOM
   element sidesteps both problems at once: this element's own
   touch-action never has to change, ever (it's simply not present/
   hit-testable via `hidden` outside the draggable window, which is a
   completely different, much safer kind of change than mutating
   touch-action on a live touch's own target), and #scene's touch-action
   is never touched at all, anywhere, so every other gesture on the page
   -- including everywhere else on the canvas outside this one small
   circle -- gets 100% ordinary native scrolling, momentum and all, with
   zero custom code standing in for it. */
.piece-less-is-more .tetra-grab-zone {
  position: absolute;
  border-radius: 50%;
  touch-action: none;
}

.piece-less-is-more .tetra-grab-zone[hidden] {
  display: none;
}

/* The legend card and the game's own button row, stacked as one bottom-
   anchored flex column (see index.html's own note): whichever of the
   two is actually visible, the stack's bottom edge always lands at the
   same 6% from the viewport bottom, and a visible button row simply
   grows the stack upward, directly above the legend, instead of being
   positioned independently of the legend's own (variable) height. */
.piece-less-is-more .bottom-stack {
  position: absolute;
  left: 50%;
  bottom: 6%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  width: min(560px, 86vw);
}

/* A caption card overlaid on the pinned graphic, near the bottom of the
   viewport. Its heading/body text is swapped by script.js as t crosses
   each chapter boundary, so the explanation progresses alongside the
   graphic instead of arriving as one block of text after it. */
.piece-less-is-more .legend {
  width: 100%;
  background: rgba(5, 2, 8, 0.78);
  border: 1px solid rgba(184, 255, 250, 0.22);
  border-radius: 12px;
  padding: 1rem 1.25rem 1.15rem;
  pointer-events: none;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}

.piece-less-is-more .legend h3 {
  color: #9fe8db;
  font-size: 1rem;
  font-weight: 600;
  margin: 0 0 0.4rem;
}

.piece-less-is-more .legend p {
  color: #cdd3da;
  font-size: 0.92rem;
  line-height: 1.55;
  margin: 0;
}

/* "Guess the Door" game controls -- the only clickable DOM this piece
   adds. Same horizontal width as the legend card (see .bottom-stack
   above), and deliberately plain: a dark, translucent pill matching the
   legend card's own border/background treatment rather than introducing
   a new visual language of its own. Unlike .legend (pointer-events:
   none, a pure caption overlay), these need pointer-events: auto to
   actually be clickable. */
/* `position: relative` makes this a positioning context for
   #gameRevealBtn (see below and index.html's own note) -- everything
   else here (the `display: flex` row) is only ever "Open selected" or
   "Play again," never both, so a plain centered row is all that
   needs to be. */
.piece-less-is-more .game-controls {
  position: relative;
  display: flex;
  justify-content: center;
  width: 100%;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}

/* Without this, the unconditional `display: flex` above outranks the
   browser's own default `[hidden] { display: none }` rule (an author
   class selector beats a UA-stylesheet attribute selector), so setting
   the `hidden` property from script.js would do nothing and the button
   row would stay visible the entire time -- caught by screenshotting the
   very first frame, where it visibly sat on top of the legend body text
   long before the game becomes interactive. */
.piece-less-is-more .game-controls[hidden] {
  display: none;
}

/* Deliberately taken *out* of .game-controls's own flex flow entirely
   -- see index.html's own note for why floating this, rather than
   giving it any kind of normal-flow slot (shared row or a row of its
   own), is what's actually needed: anything that's part of the flow
   changes that flow's own total size the moment it appears, which
   perturbs "Open selected"/"Play again"'s own position one way or
   another. `bottom: 100%` anchors this button's own bottom edge to
   .game-controls's own top edge, i.e. directly above the primary
   button row, growing further upward from there as needed -- never
   downward into the legend card directly below. */
.piece-less-is-more #gameRevealBtn {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-bottom: 0.6rem;
}

.piece-less-is-more .game-btn {
  pointer-events: auto;
  cursor: pointer;
  background: rgba(5, 2, 8, 0.78);
  border: 1px solid rgba(184, 255, 250, 0.35);
  border-radius: 8px;
  color: #cdd3da;
  font-family: inherit;
  font-size: 0.88rem;
  padding: 0.5rem 0.9rem;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.piece-less-is-more .game-btn:hover:not(:disabled) {
  background: rgba(184, 255, 250, 0.12);
  border-color: rgba(184, 255, 250, 0.6);
}

.piece-less-is-more .game-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.piece-less-is-more .game-btn-primary {
  color: #9fe8db;
  border-color: rgba(184, 255, 250, 0.55);
}

/* #gameOpenBtn and #gameNewRoundBtn are mutually exclusive -- exactly
   one hidden at all times (see script.js's own syncGameControls) --
   sharing their own isolated `.game-controls-row` (see index.html's
   own note on why that row is kept separate from "Reveal the cheat
   sheet"'s), and meant to occupy the *exact same* on-screen slot when
   swapped, so the mouse is already positioned over "Play again" the
   instant a round resolves. `justify-content: center` on that shared
   row means that only holds if the two buttons are themselves the same
   width -- "Play again" is shorter text than "Open selected," and
   without this, swapping one for the other re-centered the row and
   shifted the visible button sideways by several dozen px, measured
   directly, not just eyeballed. 132px is "Open selected"'s own natural
   width (measured at this font-size), rounded up slightly. */
.piece-less-is-more #gameOpenBtn,
.piece-less-is-more #gameNewRoundBtn {
  min-width: 132px;
}
