/* ---------------------------------------------------------------------------
   Station panels — the flat 2D layer that takes over when you click the
   speaker or the desk.

   Everything here sits on top of a still image of the room, not the live
   canvas, so none of it is competing with a render loop. That is what makes it
   cheap enough to leave open on a phone.
   --------------------------------------------------------------------------- */

.station-root {
  position: fixed;
  inset: 0;
  z-index: 40;                 /* under the pause menu (50), over the canvas */
  opacity: 0;
  transition: opacity 0.28s ease;
}
.station-root.is-open { opacity: 1; }
.station-root[hidden] { display: none !important; }

/* the frozen frame */
.station-still {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Matches the room's own look rather than resampling it smooth. */
  image-rendering: pixelated;
}

.station-scrim {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: max(3vh, env(safe-area-inset-top, 0px)) 4vw max(3vh, env(safe-area-inset-bottom, 0px));
  /* No wash and no blur: the room behind the panel is the point, so it is
     left exactly as the renderer drew it. */
  background: none;
}

.station-close {
  position: absolute;
  top: max(1.1rem, env(safe-area-inset-top, 0px));
  right: 1.1rem;
  z-index: 3;
  width: 2.4rem;
  height: 2.4rem;
  border: 1px solid rgba(238, 231, 214, 0.35);
  border-radius: 50%;
  background: rgba(12, 10, 16, 0.72);
  box-shadow: 0 0.2rem 0.7rem rgba(0, 0, 0, 0.5);
  color: #eee7d6;
  font: 1.35rem/1 var(--ui-font, "Pix32 Cond", sans-serif);
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}
.station-close:hover { background: rgba(40, 34, 50, 0.8); border-color: rgba(238, 231, 214, 0.7); }

/* Only the panel for the open station is in the layout. */
.station-root .ipod-dock,
.station-root .desk-board { display: none; }
.station-root[data-station="speaker"] .ipod-dock { display: grid; }
.station-root[data-station="desk"] .desk-board { display: block; }

/* ---------------------------------------------------------------- the player
   A 3rd-gen iPod nano, drawn rather than modelled: the squat aluminium body,
   the 2-inch screen sitting above a click wheel, in the red Product(RED)
   finish. It rides down on a dock lip so it reads as slotting into the
   speaker on the table rather than floating in front of it. */
.ipod-dock {
  position: relative;
  z-index: 2;
  display: grid;
  justify-items: center;
  /* How far down the resting position sits, so the nano's base lands in the
     speaker's own dock slot rather than floating above it. Tune this one
     number if the seat drifts. */
  --ipod-seat: 3.05rem;
  transform: translateY(-140%);
}
/* Comes down out of frame, tips level on the way, drops the last few
   millimetres and settles — a thing being seated in a dock, not a panel
   sliding on. */
.station-root.is-open .ipod-dock {
  animation: ipod-dock-in 0.78s cubic-bezier(0.32, 0.9, 0.3, 1) forwards;
}
@keyframes ipod-dock-in {
  from { transform: translateY(-140%) rotate(-4deg) scale(0.96); }
  62%  { transform: translateY(calc(var(--ipod-seat) + 0.5rem)) rotate(0.6deg) scale(1); }
  78%  { transform: translateY(calc(var(--ipod-seat) - 0.35rem)) rotate(-0.4deg); }
  90%  { transform: translateY(calc(var(--ipod-seat) + 0.16rem)) rotate(0deg); }
  to   { transform: translateY(var(--ipod-seat)) rotate(0deg) scale(1); }
}

.ipod {
  position: relative;
  /* The dock is the grid now, so the pod has to declare its own — without
     this its rows collapse, the track list grows unbounded and shoves the
     click wheel off the bottom of the screen. */
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  /* Gen 3 proportions: 52 x 70mm, so a squat body, not the tall gen 6 stick. */
  width: min(64vw, 15.5rem);
  padding: 0.5rem 0.5rem 0.55rem;
  /* Anodised aluminium: a bright top edge, a deeper body, a shadowed base. */
  border-radius: 0.85rem;
  background:
    linear-gradient(160deg, #ff5a5f 0%, #e0202c 34%, #b8121d 72%, #8e0b15 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 -2px 3px rgba(0, 0, 0, 0.45),
    inset 2px 0 3px rgba(0, 0, 0, 0.28),
    inset -2px 0 3px rgba(255, 255, 255, 0.16),
    0 1.2rem 2.4rem rgba(0, 0, 0, 0.6);
}
/* The chamfer round the face, which is what makes the metal read as metal. */
/* A dark band across the foot of the body. The real dock slot in the scene is
   black, so this gives the aluminium something to disappear into instead of
   ending on a hard red edge above it. */
.ipod::after {
  content: "";
  position: absolute;
  left: 2%;
  right: 2%;
  bottom: 0;
  height: 0.85rem;
  border-radius: 0 0 0.8rem 0.8rem;
  background: linear-gradient(rgba(10, 10, 12, 0) 0%, rgba(12, 12, 15, 0.72) 45%, #0c0c0f 100%);
  pointer-events: none;
}
.ipod::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(160deg, rgba(255,255,255,0.7), rgba(255,255,255,0) 40%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
}


/* The 2-inch screen, laid out like the real Now Playing view: a title bar
   across the top, sleeve art bottom-left, track details up the right, and
   elapsed / scrubber / remaining along the bottom. */
.ipod-screen {
  display: grid;
  aspect-ratio: 4 / 3;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "chrome chrome"
    "art    meta"
    "foot   foot";
  gap: 0.3rem 0.45rem;
  min-height: 0;
  padding: 0.3rem 0.35rem 0.32rem;
  border-radius: 0.28rem;
  /* The gen 3 UI is light, not dark — white panel, dark type. */
  background: #ffffff;
  color: #16181d;
  /* glass sunk into the aluminium */
  box-shadow:
    inset 0 0 0 1px rgba(0, 0, 0, 0.9),
    inset 0 2px 5px rgba(0, 0, 0, 0.8),
    0 1px 0 rgba(255, 255, 255, 0.28);
}

.ipod-chrome {
  grid-area: chrome;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.08rem 0.2rem;
  border-radius: 0.1rem;
  /* the pale grey bar Apple put across the top */
  background: linear-gradient(#dfe2e8, #b9bec8);
  color: #2a2d34;
  font: 0.5rem/1 var(--ui-font, "Pix32 Cond", sans-serif);
  letter-spacing: 0.04em;
}
.ipod-battery {
  width: 0.75rem;
  height: 0.36rem;
  border: 1px solid #2a2d34;
  border-radius: 1px;
  background: linear-gradient(90deg, #2a2d34 62%, transparent 62%);
  position: relative;
}
.ipod-battery::after {
  content: "";
  position: absolute;
  right: -2.5px;
  top: 50%;
  translate: 0 -50%;
  width: 1.5px;
  height: 0.16rem;
  background: #2a2d34;
}

.ipod-art {
  grid-area: art;
  width: 5.6rem;
  aspect-ratio: 1;
  object-fit: cover;
  align-self: center;
  border: 1px solid rgba(0, 0, 0, 0.18);
}

.ipod-meta {
  grid-area: meta;
  min-width: 0;
  align-self: center;
  padding-right: 0.1rem;
}
.ipod-title {
  font: 0.62rem/1.2 var(--ui-font, "Pix32 Cond", sans-serif);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ipod-artist,
.ipod-album {
  margin-top: 0.06rem;
  font: 0.52rem/1.2 var(--ui-font, "Pix32 Cond", sans-serif);
  color: #4a4d55;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ipod-album { color: #74777f; }
.ipod-album:empty { display: none; }
.ipod-count {
  margin-top: 0.22rem;
  color: #74777f;
  font: 0.5rem/1 var(--ui-font, "Pix32 Cond", sans-serif);
}

.ipod-foot {
  grid-area: foot;
  display: flex;
  align-items: center;
  gap: 0.28rem;
}
.ipod-time {
  flex: 0 0 auto;
  color: #4a4d55;
  font: 0.46rem/1 var(--ui-font, "Pix32 Cond", sans-serif);
}
.ipod-bar {
  flex: 1 1 auto;
  height: 0.26rem;
  border-radius: 0.13rem;
  background: #d8dade;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.22);
  cursor: pointer;
}
.ipod-fill {
  width: 0;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(#8fb6ee, #4f7fd0);
  transition: width 0.15s linear;
}


/* The click wheel. One ring, four printed labels, a centre button — the
   buttons are positioned on it rather than sitting in a row. */
.ipod-wheel {
  position: relative;
  width: 6.6rem;
  height: 6.6rem;
  margin: 0.55rem auto 0;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 34%, #fbf7f2, #ddd6cd 62%, #c3bbb1);
  box-shadow:
    inset 0 1px 2px rgba(255, 255, 255, 0.9),
    inset 0 -2px 4px rgba(0, 0, 0, 0.22),
    0 1px 2px rgba(0, 0, 0, 0.35);
}
.ipod-wheel::after {
  content: "";
  position: absolute;
  inset: 50% auto auto 50%;
  width: 2.7rem;
  height: 2.7rem;
  translate: -50% -50%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 36%, #fdfbf8, #e2dcd3 70%, #cac2b8);
  box-shadow: inset 0 1px 2px rgba(255,255,255,0.9), 0 1px 3px rgba(0,0,0,0.3);
}
.ipod-btn {
  position: absolute;
  border: none;
  background: none;
  color: #6f675e;
  font: 0.62rem/1 var(--ui-font, "Pix32 Cond", sans-serif);
  letter-spacing: 0.06em;
  cursor: pointer;
  padding: 0.5rem 0.6rem;
  transition: color 0.15s ease, transform 0.08s ease;
}
/* The transport glyphs are inline SVG now (see stations.js) — centred, and
   sized off the button's own type scale so they track it. */
.ipod-btn { display: inline-flex; align-items: center; justify-content: center; }
.ipod-btn svg { display: block; width: 1.5em; height: 1.5em; }
.ipod-btn.play svg { width: 2em; }
.ipod-btn:hover { color: #2b2b33; }
.ipod-btn:active { transform: scale(0.94); }
.ipod-btn.prev { left: 0.35rem; top: 50%; translate: 0 -50%; }
.ipod-btn.next { right: 0.35rem; top: 50%; translate: 0 -50%; }
.ipod-btn.play { left: 50%; bottom: 0.3rem; translate: -50% 0; }
/* MENU is printed at the top of a real one and does nothing here, so it is
   text rather than a control. */
.ipod-wheel::before {
  content: "MENU";
  position: absolute;
  left: 50%;
  top: 0.5rem;
  translate: -50% 0;
  color: #6f675e;
  font: 0.6rem/1 var(--ui-font, "Pix32 Cond", sans-serif);
  letter-spacing: 0.12em;
}

/* Under the loft the room is genuinely dim — this lifts it to about what the
   rest of the room reads at, rather than washing it. */
.station-root[data-station="desk"] .station-still { filter: brightness(1.18); }

/* ---------------------------------------------------------------- the desk */
.desk-board {
  position: relative;
  z-index: 2;
  width: min(96vw, 60rem);
  height: min(84vh, 42rem);
  /* The still looks down on the desk at about 78 degrees below horizontal
     (0.50m of drop over 0.10m of reach), so the sheets lie back by the
     complement — 14 degrees — to sit in the plane of the desktop behind them. */
  perspective: 1100px;
  perspective-origin: 50% 38%;
}

.desk-piece {
  position: absolute;
  /* To scale against the room: a sheet of paper is about 21cm, the poscas
     beside it about 13cm. The lens went from 66 to 40 degrees, which magnifies
     the desk about 1.8x, so the sheets have to grow by the same factor or they
     stop reading as paper. */
  width: clamp(7rem, 25vw, 15rem);
  /* Sheet of paper, not a square print — the art is cropped to fill it. */
  aspect-ratio: 3 / 4;
  object-fit: cover;
  /* rotateX lays it down onto the desk; the tilt then happens IN that plane,
     so a sheet turned on the desk stays flat on it. One transform rather than
     the individual properties, because the order of the two matters. */
  /* rotateZ first swings into the desk's on-screen axis, rotateX lays the
     sheet down into its plane, then the per-sheet tilt happens IN that plane. */
  transform: translate(-50%, -50%) rotateZ(-32deg) rotateX(14deg) rotateZ(var(--tilt, 0deg));
  transform-origin: 50% 50%;
  /* Contact shadow: tight and offset down-right, the way paper sits on wood.
     No border — these are loose sheets, not framed prints. */
  box-shadow: 0.15rem 0.35rem 0.5rem rgba(0, 0, 0, 0.38);
  cursor: grab;
  touch-action: none;                /* the drag is ours, not the browser's */
  user-select: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
  transition: box-shadow 0.15s ease;
}
/* Tapped: comes off the desk, squares up to camera and fills the frame. The
   transform is a full override rather than an addition, because the lying-flat
   rotations are exactly what has to go. */
.desk-piece.is-zoomed {
  left: 50% !important;
  top: 50% !important;
  width: min(74vw, 30rem);
  transform: translate(-50%, -50%) rotateX(0deg) rotateZ(0deg);
  box-shadow: 0 1.6rem 3.4rem rgba(0, 0, 0, 0.6);
  cursor: zoom-out;
  transition: transform 0.34s cubic-bezier(0.22, 1, 0.32, 1),
              width 0.34s cubic-bezier(0.22, 1, 0.32, 1),
              left 0.34s ease, top 0.34s ease, box-shadow 0.3s ease;
}
/* Everything else steps back while one is being read. */
.desk-board.has-zoom .desk-piece:not(.is-zoomed) {
  opacity: 0.45;
  pointer-events: none;
}
.desk-piece { transition: box-shadow 0.15s ease, opacity 0.25s ease; }

.desk-piece.is-held {
  cursor: grabbing;
  /* lifts off the desk a little while you hold it */
  transform: translate(-50%, -50%) rotateZ(-32deg) rotateX(14deg) rotateZ(var(--tilt, 0deg)) translateZ(0.9rem);
  box-shadow: 0.4rem 0.9rem 1.4rem rgba(0, 0, 0, 0.45);
}

.desk-hint {
  position: absolute;
  left: 50%;
  bottom: -1.6rem;
  translate: -50% 0;
  color: rgba(238, 231, 214, 0.65);
  font: 0.8rem/1 var(--ui-font, "Pix32 Cond", sans-serif);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  transition: opacity 0.4s ease;
}
.desk-hint.is-gone { opacity: 0; }

/* A hovered station gets the pointer cue, same as the records. */
#scene.hovering-station { cursor: pointer; }

@media (prefers-reduced-motion: reduce) {
  .ipod-dock { transition: none; }
  .station-root { transition: none; }
}

/* ---------------------------------------------------------------- pickups
   Tapping an object in the room that is also a piece in the Items menu opens
   its 3D preview here, over the frozen frame. Same still, same escape, but no
   camera move — you come back to exactly where you were standing. */
.pickup-root {
  position: fixed;
  inset: 0;
  z-index: 42;                 /* over the station panels, under the menu */
  opacity: 0;
  transition: opacity 0.26s ease;
}
.pickup-root.is-open { opacity: 1; }
.pickup-root[hidden] { display: none !important; }

.pickup-scrim {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-rows: 1fr auto;
  padding: max(3vh, env(safe-area-inset-top, 0px)) 4vw
           max(3vh, env(safe-area-inset-bottom, 0px));
  /* Only a light wash: the room behind is the point, same as the stations. */
  background: linear-gradient(rgba(10, 8, 14, 0.1), rgba(10, 8, 14, 0.42));
}

.pickup-viewer {
  position: relative;
  z-index: 2;
  width: 100%;
  min-height: 0;
  /* The viewer sizes its renderer off this box, so it needs real dimensions
     before mountModelViewer runs — grid gives it those. */
}
.pickup-viewer canvas { display: block; }

.pickup-card {
  position: relative;
  z-index: 2;
  justify-self: center;
  width: min(92vw, 30rem);
  padding: 0.8rem 1rem 0.9rem;
  text-align: center;
  border: 1px solid rgba(238, 231, 214, 0.28);
  border-radius: 0.4rem;
  background: rgba(14, 12, 18, 0.72);
  color: #eee7d6;
}
.pickup-name {
  font: 1.05rem/1.2 var(--ui-font, "Pix32 Cond", sans-serif);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.pickup-stats {
  display: flex;
  justify-content: center;
  gap: 1.1rem;
  margin-top: 0.35rem;
  color: rgba(238, 231, 214, 0.72);
  font: 0.72rem/1 var(--ui-font, "Pix32 Cond", sans-serif);
}
.pickup-stats i {
  font-style: normal;
  color: rgba(238, 231, 214, 0.42);
  margin-right: 0.3em;
}
.pickup-to-items {
  margin-top: 0.7rem;
  padding: 0.45rem 1.1rem;
  border: 1px solid rgba(238, 231, 214, 0.4);
  border-radius: 999px;
  background: none;
  color: #eee7d6;
  font: 0.72rem/1 var(--ui-font, "Pix32 Cond", sans-serif);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease;
}
.pickup-to-items:hover {
  background: rgba(238, 231, 214, 0.14);
  border-color: rgba(238, 231, 214, 0.8);
}

@media (prefers-reduced-motion: reduce) {
  .pickup-root { transition: none; }
}
