/* ============================================================================
   blackboxgames.net — demo
   Monochrome. Black base, neon-white accent. Game art is the only colour that
   enters the page, which is the point: the box is matte and the games glow.

   Type carries three jobs and never doubles up:
     Archivo (expanded)  — display. Machined and wide, like the object itself.
     Sora                — body. Already the studio's face, from the wordmark.
     JetBrains Mono      — data. Every real number is set as an instrument
                           readout, because they come off a live dashboard.
   ============================================================================ */

:root {
  --void:      #000000;
  --panel:     #0a0a0c;
  --rule:      rgba(255, 255, 255, 0.10);
  --rule-lit:  rgba(255, 255, 255, 0.28);
  --glow:      #ffffff;
  --dim:       #7e7e86;
  --dimmer:    #4a4a52;
  /* The one colour allowed to break the monochrome, and it earns it: this is
     the live-player indicator, and green is what "online right now" means
     everywhere. Nothing else on the page may use it. */
  --live:      #3ddc84;

  --display: 'Archivo', system-ui, sans-serif;
  --body:    'Sora', system-ui, sans-serif;
  --mono:    'JetBrains Mono', ui-monospace, monospace;

  --box:   clamp(178px, 31vmin, 352px);
  --box-x: 0px;                 /* driven by app.js: centre → left as it locks */
  --box-y: 0px;
  --gut:   clamp(20px, 5vw, 72px);

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

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

html { scroll-behavior: smooth; }

body {
  background: var(--void);
  color: var(--glow);
  font-family: var(--body);
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

::selection { background: #fff; color: #000; }

:focus-visible {
  outline: 2px solid var(--glow);
  outline-offset: 4px;
  border-radius: 2px;
}

/* --- the room --------------------------------------------------------------
   Not wallpaper. The box is a physical object, so it gets somewhere to be: a
   light source above it, a floor running back to a horizon, grain across the
   lens and a vignette closing the edges. Four flat layers, no WebGL, and the
   only thing that moves is the floor drifting toward you. */
.veil {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  transform: translate3d(var(--veil-x, 0), var(--veil-y, 0), 0);
  transition: transform 1.1s var(--ease);
}

/* the light the box stands under */
.veil-glow {
  position: absolute;
  inset: -30% -20% auto;
  height: 120%;
  background:
    radial-gradient(ellipse 46% 40% at 50% 30%, rgba(255,255,255,.085), transparent 62%),
    radial-gradient(ellipse 90% 55% at 50% 8%,  rgba(255,255,255,.05),  transparent 70%);
}

/* The floor: a plane hinged at the horizon and laid back toward the viewer.
   The container's top edge IS the horizon — that is why the grid's
   transform-origin is 50% 0 and it extends well past the bottom. */
.veil-floor {
  position: absolute;
  left: -25%;
  right: -25%;
  top: 54%;
  bottom: -6%;
  /* A short perspective crushes the whole floor into a thin band. 760px keeps
     the rows readable most of the way back to the horizon. */
  perspective: 760px;
  perspective-origin: 50% 0%;
  mask-image: linear-gradient(180deg, transparent 0%, #000 20%, #000 78%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 20%, #000 78%, transparent 100%);
}

.veil-floor-grid {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: -280%;
  transform: rotateX(77deg);
  transform-origin: 50% 0%;
  background-image:
    linear-gradient(rgba(255,255,255,.5) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.3) 1px, transparent 1px);
  background-size: 110px 110px;
  opacity: .5;
  animation: floor-drift 12s linear infinite;
}

@keyframes floor-drift {
  to { background-position: 0 110px, 0 0; }
}

/* lens grain — the one texture on the page. Static noise, stepped so it reads
   as film rather than as a shimmer. */
.veil-grain {
  position: absolute;
  inset: -120px;
  opacity: .16;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
  animation: grain-shift 1.1s steps(4) infinite;
}

@keyframes grain-shift {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(-38px, 22px); }
  50%  { transform: translate(24px, -34px); }
  75%  { transform: translate(-18px, -14px); }
  100% { transform: translate(0, 0); }
}

.veil-vignette {
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 78% 68% at 50% 46%, transparent 42%, rgba(0,0,0,.82) 100%);
}

/* --- top bar --------------------------------------------------------------- */
.topbar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 20px var(--gut);
  /* A scrim instead of mix-blend-mode: difference. Difference kept the text
     legible over game art but inverted the glass login button into something
     unrecognisable, and glass is the studio's button. */
  background: linear-gradient(180deg, rgba(0,0,0,.72), rgba(0,0,0,.28) 58%, transparent);
}

.topbar-mark {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: var(--glow);
}

.topbar-logo {
  display: block;
  height: clamp(26px, 2.3vw, 34px);
  width: auto;
}

.topbar-nav {
  display: flex;
  align-items: center;
  gap: clamp(20px, 2.6vw, 40px);
}

.topbar-nav a:not(.glass) {
  font-family: var(--mono);
  font-size: clamp(13px, 1.05vw, 15px);
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--glow);
  text-decoration: none;
  opacity: .62;
  transition: opacity .3s var(--ease);
}

.topbar-nav a:not(.glass):hover { opacity: 1; }

@keyframes glyph-turn {
  to { transform: rotate(360deg); }
}

/* ============================================================================
   THE STAGE — one sticky viewport, one box, the whole scroll run
   ============================================================================ */
.stage {
  position: relative;
  z-index: 1;
  /* height is written by app.js: 100svh hero + one beat per featured game */
}

.stage-pin {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
}

/* --- the box --------------------------------------------------------------- */
.scene {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--box);
  height: var(--box);
  margin: calc(var(--box) / -2) 0 0 calc(var(--box) / -2);
  z-index: 3;                    /* the box sits in front of the wordmark */
  /* Perspective must scale WITH the box. A fixed 1500px against a ~270px cube
     puts the camera about five box-widths away, which magnifies the near face,
     keystones the verticals and stops the cube reading as square. Tying it to
     --box keeps the same mild projection at every screen size. */
  perspective: calc(var(--box) * 14);
  /* dead centre — an off-centre origin tilts the projection and makes opposite
     edges different lengths */
  perspective-origin: 50% 50%;
  transform: translate3d(var(--box-x), var(--box-y), 0) scale(var(--box-s, 1));
  will-change: transform;
}

.box {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  will-change: transform;
}

.face {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: linear-gradient(150deg, #141418 0%, #0a0a0c 55%, #050506 100%);
  border: 1px solid rgba(255, 255, 255, 0.34);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.05),
    inset 0 22px 60px -30px rgba(255,255,255,.34),
    /* an outward rim, so a dark box on a dark page still reads as an object
       when it is only a few dozen pixels wide inside the wordmark */
    0 0 18px -4px rgba(255,255,255,.30);
  backface-visibility: hidden;
}

/* four sides carry games, top and bottom stay matte glass */
.face[data-face="0"] { transform: rotateY(0deg)   translateZ(calc(var(--box) / 2)); }
.face[data-face="1"] { transform: rotateY(90deg)  translateZ(calc(var(--box) / 2)); }
.face[data-face="2"] { transform: rotateY(180deg) translateZ(calc(var(--box) / 2)); }
.face[data-face="3"] { transform: rotateY(270deg) translateZ(calc(var(--box) / 2)); }
.face--top    { transform: rotateX(90deg)  translateZ(calc(var(--box) / 2)); }
.face--bottom { transform: rotateX(-90deg) translateZ(calc(var(--box) / 2)); }

.face-art {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0;
  filter: saturate(1.05) contrast(1.04);
  /* NO transition here. This opacity resolves through --art-o, which app.js
     rewrites every frame; a transition on it restarts each frame and never
     settles, leaving the art stuck part-faded. The scroll IS the fade. */
}

.face-art.is-loaded { opacity: var(--art-o, 1); }

/* specular: a fixed highlight that reads as a light source the box turns under */
.face-sheen {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(155deg,
      rgba(255,255,255,.30) 0%,
      rgba(255,255,255,.06) 22%,
      transparent 46%),
    linear-gradient(0deg, rgba(0,0,0,.55) 0%, transparent 42%);
}

.face--cap .face-sheen {
  background:
    linear-gradient(155deg, rgba(255,255,255,.20), transparent 55%),
    radial-gradient(circle at 50% 50%, rgba(255,255,255,.05), transparent 70%);
}

/* the box sits on something */
.box-shadow {
  position: absolute;
  left: 50%;
  top: calc(100% + 6%);
  width: 128%;
  height: 20%;
  transform: translateX(-50%) rotateX(74deg);
  background: radial-gradient(ellipse at center, rgba(255,255,255,.16), transparent 66%);
  filter: blur(20px);
  opacity: var(--shadow-o, .5);
  pointer-events: none;
}

/* --- hero copy ------------------------------------------------------------- */
.hero {
  position: absolute;
  left: 50%;
  top: 50%;
  width: min(92vw, 900px);
  transform: translate(-50%, calc(-50% + var(--hero-lift, 0px)));
  text-align: center;
  opacity: var(--hero-o, 1);
  pointer-events: none;
  z-index: 2;
}

/* The wordmark, set in type. The slot's proportions are lifted straight off the
   real logo — its cube occupies 151x168 of a 1146x276 canvas — so the hole the
   box stands in matches the mark it stands for. */
.hero-title {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--display);
  font-variation-settings: 'wdth' 122;
  font-weight: 900;
  /* 13.6vw fills ~92% of a phone. Below that the slot — and so the box that
     stands in it — shrinks to a few dozen pixels and reads as an empty gap
     rather than as the O. The rem cap keeps desktop where it was. */
  font-size: clamp(2.6rem, 13.6vw, 10.5rem);
  line-height: .84;
  letter-spacing: -.012em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* reads as light, not paint */
.hero-word {
  color: transparent;
  background: linear-gradient(180deg, #fff 12%, #cfcfd6 58%, #7d7d86 100%);
  -webkit-background-clip: text;
  background-clip: text;
}

.hero-slot {
  display: block;
  flex: 0 0 auto;
  width: .78em;
  height: .87em;
  margin: 0 .04em;
}

.hero-line {
  margin-top: clamp(18px, 3vh, 30px);
  font-size: clamp(.9rem, 1.5vw, 1.06rem);
  color: var(--dim);
  letter-spacing: .01em;
}

.hero-line strong {
  font-family: var(--mono);
  font-weight: 500;
  color: var(--glow);
}

.hero-cue {
  margin-top: clamp(26px, 5vh, 54px);
  display: inline-flex;
  align-items: center;
  gap: 14px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--dimmer);
}

/* A rule on one side only shifts the text off centre. Mirroring it keeps the
   words centred under the wordmark and still reads as a direction. */
.hero-cue-rule,
.hero-cue::after {
  content: '';
  display: block;
  width: 46px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--rule-lit));
  animation: cue-slide 2.6s var(--ease) infinite;
}

.hero-cue::after { background: linear-gradient(90deg, var(--rule-lit), transparent); }

@keyframes cue-slide {
  0%, 100% { transform: translateX(0);    opacity: .35; }
  50%      { transform: translateX(10px); opacity: 1; }
}

/* --- per-game readouts ----------------------------------------------------- */
.readouts {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
}

.readout {
  position: absolute;
  top: 50%;
  right: var(--gut);
  width: min(40vw, 430px);
  transform: translateY(-50%);
  opacity: 0;
  visibility: hidden;
}

.readout.is-live {
  visibility: visible;
  pointer-events: auto;
}

.readout-title {
  font-family: var(--display);
  font-variation-settings: 'wdth' 112;
  font-weight: 800;
  font-size: clamp(1.7rem, 3.9vw, 3.15rem);
  line-height: .96;
  letter-spacing: -.015em;
  text-transform: uppercase;
}

.readout-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 10px clamp(20px, 3vw, 40px);
  margin-top: clamp(24px, 4vh, 38px);
  padding-top: 22px;
  border-top: 1px solid var(--rule);
}

.stat-k {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--dimmer);
}

.stat-v {
  margin-top: 7px;
  font-family: var(--mono);
  font-weight: 500;
  font-size: clamp(1.15rem, 2.3vw, 1.72rem);
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}

/* live figure gets a pulse, because it is the one number that moves */
.stat--live .stat-v { position: relative; padding-left: 17px; }

.stat--live .stat-v::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  width: 7px;
  height: 7px;
  margin-top: -3px;
  border-radius: 50%;
  background: var(--live);
  animation: live-pulse 2.1s ease-in-out infinite;
}

@keyframes live-pulse {
  0%, 100% { opacity: 1;  box-shadow: 0 0 0 0 rgba(61, 220, 132, .55), 0 0 8px rgba(61,220,132,.9); }
  70%      { opacity: .5; box-shadow: 0 0 0 9px rgba(61, 220, 132, 0),   0 0 8px rgba(61,220,132,.3); }
}

.readout-cta { margin-top: clamp(24px, 4vh, 36px); }

/* --- end of the box run ---------------------------------------------------- */
.stage-out {
  position: absolute;
  left: 50%;
  bottom: clamp(60px, 12vh, 130px);
  transform: translateX(-50%);
  z-index: 4;
  text-align: center;
  opacity: 0;
  visibility: hidden;
}

.stage-out.is-live { visibility: visible; }

/* --- liquid glass ---------------------------------------------------------- */
.glass {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: .8em;
  padding: 1.02em 2.15em;
  border-radius: 999px;
  overflow: hidden;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--glow);
  text-decoration: none;
  isolation: isolate;
  border: 1px solid rgba(255,255,255,.24);
  background:
    linear-gradient(180deg,
      rgba(255,255,255,.17) 0%,
      rgba(255,255,255,.05) 40%,
      rgba(255,255,255,.02) 100%);
  backdrop-filter: blur(20px) saturate(170%);
  -webkit-backdrop-filter: blur(20px) saturate(170%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.55),
    inset 0 -1px 0 rgba(255,255,255,.09),
    0 14px 44px -16px rgba(255,255,255,.34);
  transition: transform .45s var(--ease), box-shadow .45s var(--ease),
              border-color .45s var(--ease);
}

/* the specular sweep — a light passing across the surface, not a colour wash */
.glass::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(105deg,
    transparent 12%,
    rgba(255,255,255,.42) 46%,
    transparent 74%);
  transform: translateX(-130%);
  transition: transform .85s var(--ease);
}

.glass:hover {
  transform: translateY(-2px);
  border-color: rgba(255,255,255,.44);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.7),
    inset 0 -1px 0 rgba(255,255,255,.12),
    0 20px 56px -16px rgba(255,255,255,.46);
}

.glass:hover::before { transform: translateX(130%); }

.glass::after {
  content: '';
  width: 6px;
  height: 6px;
  border-top: 1px solid currentColor;
  border-right: 1px solid currentColor;
  transform: rotate(45deg);
  transition: transform .45s var(--ease);
}

.glass:hover::after { transform: rotate(45deg) translate(2px, -2px); }

/* compact glass — top bar, cards */
.glass--sm {
  padding: .68em 1.3em;
  font-size: 11px;
  letter-spacing: .12em;
  gap: .6em;
}

.glass--sm::after { width: 5px; height: 5px; }

/* ============================================================================
   THE STUDIO — one person per beat, alternating sides
   ============================================================================ */
.studio {
  position: relative;
  z-index: 2;
  /* clears the fixed top bar when jumping here from a nav link */
  scroll-margin-top: 76px;
  padding: clamp(90px, 16vh, 190px) var(--gut) clamp(70px, 12vh, 140px);
  /* Translucent, not solid. A solid panel here painted over the fixed floor
     grid and the room simply vanished behind the team. This keeps enough
     separation to sit the copy on while the grid still reads through it. */
  background: linear-gradient(180deg,
    transparent,
    rgba(10, 10, 12, .55) 18%,
    rgba(10, 10, 12, .55));
}

.studio-head {
  max-width: 1220px;
  margin: 0 auto clamp(50px, 9vh, 110px);
  text-align: center;
}

.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--dimmer);
}

.studio-title {
  margin-top: 16px;
  font-family: var(--display);
  font-variation-settings: 'wdth' 120;
  font-weight: 900;
  font-size: clamp(2.1rem, 7vw, 5.2rem);
  line-height: .92;
  letter-spacing: -.02em;
  text-transform: uppercase;
}

.roster {
  max-width: 1160px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: clamp(56px, 11vh, 128px);
}

.member {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  align-items: center;
  gap: clamp(24px, 5vw, 72px);
  opacity: 0;
  transform: translateY(38px);
  transition: opacity .9s var(--ease), transform .9s var(--ease);
}

.member.is-in { opacity: 1; transform: none; }

/* alternate: portrait right, copy left */
.member--flip .member-portrait { order: 2; }
.member--flip .member-copy     { order: 1; text-align: right; }
.member--flip .member-rule     { margin-left: auto; }

.member-portrait {
  position: relative;
  aspect-ratio: 5 / 6;
  display: grid;
  place-items: center;
}

.member-portrait::before {
  content: '';
  position: absolute;
  inset: 12%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,.09), transparent 68%);
  filter: blur(22px);
}

.silhouette {
  position: relative;
  width: 78%;
  height: auto;
  fill: none;
  stroke: var(--glow);
  stroke-width: 1.6;
  stroke-linecap: round;
  filter: drop-shadow(0 0 14px rgba(255,255,255,.55))
          drop-shadow(0 0 42px rgba(255,255,255,.24));
}

/* the real Roblox character, pulled live */
.member-avatar {
  position: relative;
  width: 88%;
  height: auto;
  filter: drop-shadow(0 0 30px rgba(255,255,255,.30))
          drop-shadow(0 14px 34px rgba(0,0,0,.85));
}

.member-portrait.has-avatar::before {
  inset: 18% 6% 10%;
  background: radial-gradient(circle, rgba(255,255,255,.14), transparent 70%);
}

.member-link {
  color: inherit;
  text-decoration: none;
  transition: opacity .3s var(--ease);
}

.member-link:hover { opacity: .62; }

.member-name {
  font-family: var(--display);
  font-variation-settings: 'wdth' 114;
  font-weight: 800;
  font-size: clamp(1.6rem, 4.4vw, 3.1rem);
  line-height: 1;
  letter-spacing: -.015em;
  text-transform: uppercase;
}

.member-handle {
  margin-top: 10px;
  font-family: var(--mono);
  font-size: clamp(11px, 1vw, 13px);
  letter-spacing: .1em;
  color: var(--dimmer);
}

.member-role {
  font-family: var(--mono);
  font-size: clamp(13px, 1.5vw, 19px);
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--dim);
}

.member-rule {
  width: 54px;
  height: 1px;
  margin: 20px 0;
  background: var(--rule-lit);
}

/* ============================================================================
   FOOTER
   ============================================================================ */
.foot {
  position: relative;
  z-index: 2;
  padding: clamp(52px, 10vh, 108px) var(--gut) clamp(26px, 4vh, 40px);
  background: var(--panel);
  border-top: 1px solid var(--rule);
}

.foot-top {
  max-width: 1160px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: clamp(40px, 7vw, 96px);
  padding-bottom: clamp(38px, 6vh, 68px);
}

.foot-logo {
  display: block;
  height: clamp(34px, 4.4vw, 58px);
  width: auto;
  max-width: 100%;
}

.foot-count {
  list-style: none;
  margin-top: 26px;
  display: grid;
  gap: 9px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--dimmer);
}

.foot-count strong {
  display: inline-block;
  min-width: 4.4em;
  font-weight: 500;
  font-size: 14px;
  color: var(--glow);
  font-variant-numeric: tabular-nums;
}

.foot-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 148px), 1fr));
  gap: clamp(26px, 4vw, 48px);
}

.foot-h {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--dimmer);
  padding-bottom: 14px;
  border-bottom: 1px solid var(--rule);
}

.foot-list {
  list-style: none;
  margin-top: 16px;
  display: grid;
  gap: 11px;
}

.foot-list a {
  display: inline-block;
  font-size: .92rem;
  color: var(--dim);
  text-decoration: none;
  transition: color .3s var(--ease), transform .3s var(--ease);
}

.foot-list a:hover { color: var(--glow); transform: translateX(3px); }

.foot-bottom {
  max-width: 1160px;
  margin: 0 auto;
  padding-top: clamp(20px, 3vh, 30px);
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--dimmer);
}

@media (max-width: 760px) {
  .foot-top { grid-template-columns: 1fr; }
}

/* ============================================================================
   ALL GAMES — what the CTA opens, so the button is never a dead link
   ============================================================================ */
.sheet {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  /* an implicit `auto` column sizes to its widest child and lets the game grid
     push past the viewport — pin it so children can never exceed the sheet */
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  gap: clamp(26px, 5vh, 52px);
  padding: clamp(26px, 6vh, 74px) var(--gut);
  overflow-y: auto;
  background: rgba(0, 0, 0, .82);
  backdrop-filter: blur(26px) saturate(140%);
  -webkit-backdrop-filter: blur(26px) saturate(140%);
  opacity: 0;
  visibility: hidden;
  transition: opacity .5s var(--ease), visibility .5s;
}

.sheet.is-open { opacity: 1; visibility: visible; }

.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: 1160px;
  width: 100%;
  margin: 0 auto;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--rule);
}

.sheet-close {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1px solid var(--rule-lit);
  background: transparent;
  color: var(--glow);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  transition: background .3s var(--ease), transform .3s var(--ease);
}

.sheet-close:hover { background: rgba(255,255,255,.1); transform: rotate(90deg); }

.sheet-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 344px), 1fr));
  gap: clamp(16px, 2vw, 28px);
  max-width: 1160px;
  width: 100%;
  margin: 0 auto;
}

.tile {
  display: flex;
  align-items: flex-start;
  gap: 20px;
  padding: 20px;
  border: 1px solid var(--rule);
  border-radius: 18px;
  color: var(--glow);
  background: rgba(255,255,255,.025);
  transition: border-color .35s var(--ease), background .35s var(--ease),
              transform .35s var(--ease);
}

.tile:hover {
  border-color: var(--rule-lit);
  background: rgba(255,255,255,.06);
  transform: translateY(-3px);
}

.tile-art {
  flex: 0 0 auto;
  width: 104px;
  height: 104px;
  border-radius: 14px;
  background-size: cover;
  background-position: center;
  box-shadow: 0 10px 30px -12px rgba(0,0,0,.9);
}

.tile-copy {
  display: grid;
  gap: 14px;
  min-width: 0;
  justify-items: start;
}

.tile-name {
  font-size: 1.02rem;
  font-weight: 400;
  line-height: 1.3;
}

.tile-stats {
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
}

.tile-stats dt {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--dimmer);
}

.tile-stats dd {
  margin-top: 5px;
  font-family: var(--mono);
  font-size: .98rem;
  letter-spacing: -.01em;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}

/* ============================================================================
   RESPONSIVE — under 900px the box stays centred and the readout drops below it
   ============================================================================ */
@media (max-width: 900px) {
  :root { --box: clamp(150px, 40vmin, 260px); }

  /* No room for the text links beside the logo and the button at this width.
     The footer carries the full navigation, and the page is one scroll anyway.
     Keyed off .glass rather than :last-child so re-ordering the nav cannot
     silently hide the button instead. */
  .topbar-nav a:not(.glass) { display: none; }

  /* the inactive-panel slide is a big fraction of a narrow screen */
  .readout { --slide: .45; }

  /* one clause per line instead of sentences wrapping mid-phrase */
  .hero-clause { display: block; }
  .hero-line   { line-height: 1.85; }

  /* the mirrored rules eat too much of a narrow line — drop them and let the
     text centre on its own */
  .hero-cue-rule,
  .hero-cue::after { display: none; }
  .hero-cue { gap: 0; }

  .readout {
    top: auto;
    bottom: clamp(46px, 11vh, 90px);
    right: var(--gut);
    left: var(--gut);
    width: auto;
    transform: none;
    text-align: center;
  }

  .readout-stats   { justify-content: center; }

  .member {
    grid-template-columns: 1fr;
    gap: 22px;
    text-align: center;
  }

  .member-portrait { max-width: 230px; margin: 0 auto; }
  .member--flip .member-portrait { order: 0; }
  .member--flip .member-copy     { order: 0; text-align: center; }
  .member-rule,
  .member--flip .member-rule { margin: 16px auto; }
}

/* ============================================================================
   REDUCED MOTION — the box still turns, because the turn IS the navigation.
   Everything ambient stops: no idle tumble, no parallax, no sweeps, no pulse.
   ============================================================================ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .topbar-glyph,
  .hero-cue-rule,
  .stat--live .stat-v::before { animation: none; }

  .veil { transition: none; }

  .glass::before { display: none; }

  .member {
    opacity: 1;
    transform: none;
    transition: none;
  }
}
