@font-face {
  font-family: "Jersey 10";
  src: url("../assets/fonts/Jersey10-Regular.ttf") format("truetype");
  font-style: normal;
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "Bitcount Prop Single";
  src: url("../assets/fonts/BitcountPropSingle-Regular.ttf") format("truetype");
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  /* Bitcount renders noticeably larger than Jersey 10 at the same point size.
     size-adjust scales every glyph (and its metrics) down to 78%, so existing
     font-size values land at the intended visual size without touching any
     selectors. Blog-monitor text auto-refits (JS binary-search on font-size),
     so it compensates for this on its own. */
  size-adjust: 78%;
}

:root {
  --bg-dark: #040706;
  --hud: #d8d0a7;
  --hud-bright: #fff2bb;
  --hud-muted: rgba(216, 208, 167, 0.62);
  --hud-faint: rgba(216, 208, 167, 0.18);
  --hud-border: rgba(232, 225, 185, 0.5);
  --hud-panel-border: rgba(216, 208, 167, 0.18);
  --hud-corner: rgba(255, 242, 187, 0.74);
  --hud-corner-soft: rgba(255, 242, 187, 0.5);
  --screen-frame-gap: 1.1vh;
  --amber: #f0a23c;
  --cyan: #7fbcc3;
  --screen-black: #020302;
  --screen-green: #b7c8ad;
  --font-terminal: "Jersey 10", "Lucida Console", "Cascadia Mono", "Cascadia Code", Consolas, "Courier New", monospace;
  /* Jersey 15 has been retired — --font-title is now Jersey 10 too. Kept as a
     separate token so "bright/title text" stays semantically distinct from
     plain terminal text and can diverge again later if needed. */
  --font-title: "Jersey 10", "Lucida Console", "Cascadia Mono", "Cascadia Code", Consolas, "Courier New", monospace;
  /* Faded / de-emphasized text (the .text-muted family + panel sub-text). */
  --font-faded: "Bitcount Prop Single", "Jersey 10", "Lucida Console", "Cascadia Mono", "Cascadia Code", Consolas, "Courier New", monospace;
  --text-wear-mask: url("../assets/textures/wear-text.webp");
  --title-wear-mask: url("../assets/textures/wear-title.webp");
  --surface-wear-mask: url("../assets/textures/wear-surface.webp");
  --text-wear-size: 96px 64px;
  --title-wear-size: 280px 150px;
  --surface-wear-size: 180px 120px;
  --project-bob-duration: 9.5s;
  --project-bob-top: -5px;
  --project-bob-bottom: 6px;
}

@property --project-shadow-lift {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

* {
  box-sizing: border-box;
}

html,
body {
  min-height: 100%;
}

body {
  margin: 0;
  overflow: hidden;
  background: var(--bg-dark);
  color: var(--hud);
  font-family: var(--font-terminal);
}

a {
  color: inherit;
}

.scene {
  position: relative;
  min-height: 100vh;
  overflow: clip;
  isolation: isolate;
  background: var(--bg-dark);
}

.scene::before,
.scene::after,
.atmosphere {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.scene::after {
  content: "";
  z-index: 0;
  background-image: url("../assets/backgrounds/background.jpg");
  background-position: center center;
  background-size: cover;
  transform: scale(1);
  transform-origin: 50% 50%;
  transition: transform 680ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  will-change: transform;
}

.scene.is-projects-open::after,
.scene.is-blog-open::after {
  transform: scale(1.035);
}

.scene::before {
  content: "";
  z-index: 1;
  background:
    radial-gradient(circle at 50% 42%, rgba(127, 188, 195, 0.12), transparent 34%),
    linear-gradient(90deg, rgba(0, 0, 0, 0.56), transparent 18%, transparent 82%, rgba(0, 0, 0, 0.62)),
    linear-gradient(180deg, rgba(0, 0, 0, 0.5), transparent 18%, transparent 76%, rgba(0, 0, 0, 0.72));
}

.atmosphere {
  z-index: 2;
  opacity: 0.34;
  background:
    radial-gradient(circle at 13% 29%, rgba(216, 208, 167, 0.18) 0 1px, transparent 2px),
    radial-gradient(circle at 61% 19%, rgba(240, 162, 60, 0.18) 0 1px, transparent 2px),
    radial-gradient(circle at 76% 63%, rgba(127, 188, 195, 0.12) 0 1px, transparent 2px),
    repeating-linear-gradient(92deg, transparent 0 23px, rgba(216, 208, 167, 0.05) 24px, transparent 25px);
  background-size: 171px 113px, 211px 157px, 263px 181px, 100% 100%;
}

.archive-stage {
  position: relative;
  z-index: 3;
  width: 100%;
  min-height: 100vh;
  perspective: 1200px;
  /* No clip-path: physical-looking objects (the monitor rig, the lower
     panel, the cartridge rack, the blog screens) are meant to extend
     under/past the holographic frame line. The frame is purely visual
     ornamentation drawn over the top via ::before — the body's
     overflow:hidden + .scene's overflow:clip already clip everything
     at the viewport edge, which is what physical objects want. The few
     elements that ARE part of the hologram (BACK TO SCREEN, label
     cards, the corner HUDs) stay within the frame's bounds via their
     own positioning, no clipping needed. */
}

.archive-stage::before {
  content: "";
  position: absolute;
  z-index: 6;
  inset: var(--screen-frame-gap);
  pointer-events: none;
  background:
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) left top / 1.25rem 2px no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) left top / 2px 1.25rem no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) right top / 1.25rem 2px no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) right top / 2px 1.25rem no-repeat,
    linear-gradient(rgba(255, 242, 187, 0.38), rgba(255, 242, 187, 0.38)) left bottom / 1.05rem 2px no-repeat,
    linear-gradient(rgba(255, 242, 187, 0.38), rgba(255, 242, 187, 0.38)) left bottom / 2px 1.05rem no-repeat,
    linear-gradient(rgba(255, 242, 187, 0.38), rgba(255, 242, 187, 0.38)) right bottom / 1.05rem 2px no-repeat,
    linear-gradient(rgba(255, 242, 187, 0.38), rgba(255, 242, 187, 0.38)) right bottom / 2px 1.05rem no-repeat,
    linear-gradient(var(--hud-panel-border), var(--hud-panel-border)) left 1px top 1px / calc(100% - 2px) 1px no-repeat,
    linear-gradient(var(--hud-panel-border), var(--hud-panel-border)) left 1px bottom 1px / calc(100% - 2px) 1px no-repeat,
    linear-gradient(var(--hud-panel-border), var(--hud-panel-border)) left 1px top 1px / 1px calc(100% - 2px) no-repeat,
    linear-gradient(var(--hud-panel-border), var(--hud-panel-border)) right 1px top 1px / 1px calc(100% - 2px) no-repeat;
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: 0 0;
  mask-position: 0 0;
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

.brand-hud {
  position: absolute;
  top: calc(var(--screen-frame-gap) * 2);
  left: calc(var(--screen-frame-gap) * 2);
  display: flex;
  align-items: flex-start;
  gap: 5.6rem;
  color: rgba(232, 225, 185, 0.84);
  text-shadow: 0 0 7px rgba(216, 208, 167, 0.2);
}

.system-readout,
.session-hud,
.bottom-hud,
.hud-panel,
.label-card {
  text-shadow: 0 0 6px rgba(216, 208, 167, 0.22);
}

.system-readout {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 0.1rem;
  min-width: 5.4rem;
  padding: 0.72rem 0.86rem;
  font-size: 1.2rem;
  color: var(--hud-muted);
  isolation: isolate;
}

.system-readout::before,
.session-hud::before {
  content: "";
  position: absolute;
  z-index: 0;
  top: 0;
  pointer-events: none;
  background:
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) left top / 1rem 2px no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) left top / 2px 1rem no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) right top / 1rem 2px no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) right top / 2px 1rem no-repeat,
    linear-gradient(rgba(255, 242, 187, 0.38), rgba(255, 242, 187, 0.38)) left bottom / 0.85rem 2px no-repeat,
    linear-gradient(rgba(255, 242, 187, 0.38), rgba(255, 242, 187, 0.38)) left bottom / 2px 0.85rem no-repeat,
    linear-gradient(rgba(255, 242, 187, 0.38), rgba(255, 242, 187, 0.38)) right bottom / 0.85rem 2px no-repeat,
    linear-gradient(rgba(255, 242, 187, 0.38), rgba(255, 242, 187, 0.38)) right bottom / 2px 0.85rem no-repeat;
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

.system-readout::before {
  left: 0;
  width: 9.4rem;
  height: 100%;
}

.brand-lockup h1 {
  margin: 0;
  color: transparent;
  background:
    linear-gradient(180deg, rgba(255, 249, 207, 0.94), rgba(223, 214, 164, 0.82) 46%, rgba(178, 173, 134, 0.68)),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.28) 0 2px, transparent 2px 8px),
    radial-gradient(circle at 14% 18%, transparent 0 3px, rgba(255, 244, 189, 0.32) 4px, transparent 7px),
    radial-gradient(circle at 67% 71%, rgba(65, 62, 47, 0.52) 0 2px, transparent 4px);
  background-size: 100% 100%, 11px 100%, 43px 29px, 37px 31px;
  background-clip: text;
  -webkit-background-clip: text;
  font-family: var(--font-title);
  font-size: 6rem;
  line-height: 0.86;
  font-weight: 400;
  -webkit-mask-image: var(--title-wear-mask);
  mask-image: var(--title-wear-mask);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--title-wear-size);
  mask-size: var(--title-wear-size);
  -webkit-text-fill-color: transparent;
}

.brand-lockup p {
  margin: 0.82rem 0 0 -1px;
  color: rgba(232, 225, 185, 0.66);
  font-size: 1.42rem;
}

.session-hud {
  position: absolute;
  top: calc(var(--screen-frame-gap) * 2);
  right: calc(var(--screen-frame-gap) * 2);
  display: grid;
  gap: 0.1rem;
  min-width: 6.8rem;
  padding: 0.72rem 0.86rem;
  color: var(--hud-muted);
  font-size: 1.06rem;
  isolation: isolate;
}

.session-hud::before {
  right: 0;
  width: 7.6rem;
  height: 100%;
}

.session-hud .readout-value {
  color: rgba(232, 225, 185, 0.82);
  font-size: 1.08rem;
}

.session-hud .readout-value:not(:last-child) {
  margin-bottom: 0.18em;
}

.project-zone,
.blog-zone {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.project-zone {
  z-index: 3;
}

.blog-zone {
  z-index: 2;
}

.scene.is-blog-staging .blog-zone,
.scene.is-blog-open .blog-zone,
.scene.is-blog-closing .blog-zone {
  z-index: 4;
}

.project-rig {
  position: absolute;
  z-index: 2;
  top: 23.5vh;
  left: 27.2vw;
  display: block;
  width: var(--project-rig-width, clamp(260px, 23vw, 480px));
  pointer-events: none;
  transform: none;
  transform-origin: 0 0;
  backface-visibility: hidden;
  /* Rig moves at t=0 in both directions. On open the panel waits for the
     rig to settle (the panel's own transition-delay handles that). On close
     the whole scene now travels home at once — no two-stage wait. */
  transition: transform 680ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  will-change: transform;
}

.scene.is-projects-open .project-rig,
.scene.is-projects-closing .project-rig,
.scene.is-blog-closing .project-rig {
  /* Capture clicks so clicks on the monitor frame (or any transparent area
     of the rig's bounding box) don't fall through to the scene's
     close-on-background handler. The rig itself has no click action — it
     just absorbs the event. */
  pointer-events: auto;
}

.scene.is-projects-open .project-rig {
  transform: var(--project-rig-transform, none);
}

.scene.is-blog-open .project-rig {
  pointer-events: none;
  transform: translate3d(-62vw, 0, 0);
}

.project-bob {
  position: relative;
  display: block;
  width: 100%;
  animation: project-hover var(--project-bob-duration) ease-in-out infinite;
  transform-origin: 50% 58%;
  backface-visibility: hidden;
}

.project-plane {
  position: relative;
  z-index: 2;
  width: 100%;
  aspect-ratio: 1386 / 890;
  --project-shadow-lift-max: 5%;
  /* Both the closed and open transforms use the same function structure
     (perspective + three rotations) so CSS interpolation animates each
     rotation cleanly from its rest angle to zero, instead of trying to
     decompose two structurally different transform lists. */
  transform: perspective(900px) rotateZ(14deg) rotateX(-8deg) rotateY(17deg);
  transform-origin: 50% 58%;
  backface-visibility: hidden;
  /* Plane rotates at t=0 in both directions. The shadow gradient fades in
     sync via its own opacity transition (same 680ms curve). */
  transition: transform 680ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
}

.project-raster-layer {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: 200%;
  height: 200%;
  transform: scale(0.5);
  transform-origin: 0 0;
}

@keyframes project-hover {
  0%,
  100% {
    transform: translateY(var(--project-bob-top));
  }

  50% {
    transform: translateY(var(--project-bob-bottom));
  }
}

@keyframes project-shadow-hover {
  0%,
  100% {
    --project-shadow-lift: var(--project-shadow-lift-max);
  }

  50% {
    --project-shadow-lift: 0%;
  }
}

.project-plane::after {
  content: "";
  position: absolute;
  z-index: 3;
  inset: 0;
  pointer-events: none;
  --project-shadow-lift: 0%;
  background: linear-gradient(-19deg, rgba(0, 0, 0, 0.6) calc(23% - var(--project-shadow-lift)), rgba(0, 0, 0, 0.5) calc(25% - var(--project-shadow-lift)), rgba(0, 0, 0, 0.4) calc(59% - var(--project-shadow-lift)), rgba(0, 0, 0, 0.3) calc(61% - var(--project-shadow-lift)), rgba(0, 0, 0, 0.2) calc(63% - var(--project-shadow-lift)), rgba(0, 0, 0, 0.1) calc(65% - var(--project-shadow-lift)), rgba(0, 0, 0, 0.05) calc(67% - var(--project-shadow-lift)), rgba(0, 0, 0, 0.02) calc(69% - var(--project-shadow-lift)), rgba(0, 0, 0, 0.01) calc(71% - var(--project-shadow-lift)), transparent);
  animation: project-shadow-hover var(--project-bob-duration) ease-in-out infinite;
  /* The shadow gradient is the 3D lighting cue for the plane's rotated pose.
     It needs to fade with the rotation, not pop on/off. Opacity rides the
     same 680ms curve as the plane transform — when the plane is flat (open),
     opacity is 0; when the plane is in its tilted rest pose, opacity is 1.
     The keyframe animation (which animates the gradient stops in sync with
     the bob) stays paused while the shadow is invisible — see
     .is-projects-open / .is-projects-closing rules. */
  opacity: 1;
  transition: opacity 680ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  -webkit-mask-image:
    url("../assets/frames/project-screen_cropped.webp"),
    linear-gradient(#000, #000);
  mask-image:
    url("../assets/frames/project-screen_cropped.webp"),
    linear-gradient(#000, #000);
  -webkit-mask-position:
    0 0,
    46.111% 42.939%;
  mask-position:
    0 0,
    46.111% 42.939%;
  -webkit-mask-size:
    100% 100%,
    93.038% 96.618%;
  mask-size:
    100% 100%,
    93.038% 96.618%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-composite: source-over;
  mask-composite: add;
}

.project-frame,
.blog-frame {
  position: relative;
  z-index: 2;
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;
  user-select: none;
  backface-visibility: hidden;
}

.project-display {
  position: absolute;
  z-index: 1;
  left: 16.306%;
  top: 9.214%;
  width: 67.316%;
  height: 72.584%;
  overflow: hidden;
  background: var(--screen-black);
  pointer-events: auto;
  cursor: pointer;
  isolation: isolate;
}

/* The screen itself enters projects mode from home. Once projects is open,
   image media can be tapped again to view the raw screenshot fullscreen. */
.scene.is-projects-closing .project-display,
.scene.is-blog-open .project-display,
.scene.is-blog-closing .project-display {
  pointer-events: none;
  cursor: default;
}

.scene.is-projects-open .project-display {
  pointer-events: auto;
  cursor: zoom-in;
}

.scene.is-projects-open .project-display[data-current-media-type="video"] {
  cursor: pointer;
}

.project-display::after,
.blog-panel::after {
  content: "";
  position: absolute;
  z-index: 2;
  inset: 0;
  pointer-events: none;
  background:
    repeating-linear-gradient(0deg, rgba(255, 246, 199, 0.12) 0 1px, transparent 1px 4px),
    radial-gradient(circle at 78% 18%, rgba(255, 255, 255, 0.1), transparent 22%);
  opacity: 0.34;
}

.project-shot {
  position: absolute;
  z-index: 1;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter:
    saturate(var(--project-shot-saturation, 100%))
    brightness(var(--project-shot-value, 100%));
  transform: translateY(0);
  transition: transform 780ms cubic-bezier(0.22, 0.8, 0.28, 1);
  will-change: transform;
}

.project-display.is-resetting .project-shot {
  transition: none;
}

.project-shot--next {
  visibility: hidden;
  transform: translateY(100%);
}

.project-shot--next.is-ready {
  visibility: visible;
}

.project-display.is-swiping .project-shot--current {
  transform: translateY(-100%);
}

.project-display.is-swiping .project-shot--next {
  transform: translateY(0);
}

.project-lower-panel {
  --project-panel-open-x: 0px;
  --project-panel-open-y: 0px;
  --project-panel-open-closed-y: -200px;
  --project-panel-home-x: 0px;
  --project-panel-home-closed-y: -200px;
  --project-panel-home-scale: 1;
  --project-panel-width: 720px;
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: var(--project-panel-width);
  /* Container query against panel width: lets text inside (button labels,
     side strip lines, etc.) scale proportionally to the panel — so a wider
     window grows the buttons' text instead of leaving them swimming in
     empty space. */
  container-type: inline-size;
  container-name: project-lower-panel;
  pointer-events: none;
  visibility: hidden;
  transform: translate3d(var(--project-panel-home-x), var(--project-panel-home-closed-y), 0)
    perspective(900px)
    rotateZ(14deg)
    rotateX(-8deg)
    rotateY(17deg)
    scale(var(--project-panel-home-scale));
  transform-origin: 50% 0%;
  backface-visibility: hidden;
  contain: layout paint;
  /* Keep the lower UI outside the monitor's scaled 3D subtree so text/buttons
     stay their intended size. In its open resting pose it is laid out with
     normal left/top coordinates, not a flat 3D transform, so the frame image
     can paint sharply instead of being sampled from a composited texture. */
  transition:
    visibility 0s linear 680ms,
    transform 680ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  will-change: transform;
}

.project-lower-panel-frame {
  position: relative;
  z-index: 2;
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;
  user-select: none;
}

/* ------- Mobile lower panel container ------- */
/* Hidden on desktop; the mobile media query at the bottom of this file flips
   it on when projects mode opens AND we're in the mobile breakpoint. Width,
   top, and left are set inline by JS to match the computed mobile layout.
   z-index 1 puts it BELOW .project-rig (z:2) so the staged open/close
   animation actually reads as the panel sliding out from / back behind the
   rig's monitor body. */
.project-lower-panel-mb {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  display: none;
  width: 0;
  container-type: inline-size;
  container-name: project-lower-panel-mb;
  pointer-events: none;
  user-select: none;
  /* Home pose — panel tucked INSIDE the home rig's inner-screen area at
     small scale + the plane's resting tilt. JS computes home-dx / home-dy
     / home-scale from the home rig's actual inner-screen rect (not just
     the rig's bounding body), since the mobile panel image has a
     different aspect ratio than the rig and a body-bottom anchor would
     leave it sticking out horizontally. transform-origin: 50% 0% so the
     panel scales about its top-center — when the close transitions back
     to this pose, the panel's top-center lands flush with the home rig's
     inner-screen top-center.

     This pose serves DOUBLE DUTY: it's the staging start for the OPEN
     transition (panel transitions FROM this pose TO the open pose), and
     the end pose for the CLOSE transition (panel transitions BACK to it).
     Putting it on the base style means both directions inherit the same
     home pose with no class-specific override needed. */
  translate: var(--panel-mb-home-dx, 0px) var(--panel-mb-home-dy, 0px);
  scale: var(--panel-mb-home-scale, 1);
  transform: perspective(900px) rotateZ(14deg) rotateX(-8deg) rotateY(17deg);
  transform-origin: 50% 0%;
  will-change: transform;
  backface-visibility: hidden;
}

.project-lower-panel-mb-frame {
  position: relative;
  z-index: 2;
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;
  user-select: none;
}

.project-lower-screen {
  position: absolute;
  z-index: 1;
  overflow: hidden;
  color: rgba(216, 208, 167, 0.82);
  background:
    radial-gradient(circle at 18% 12%, rgba(127, 188, 195, 0.13), transparent 34%),
    linear-gradient(180deg, rgba(14, 18, 15, 0.94), rgba(2, 3, 2, 0.98));
  box-shadow:
    inset 0 0 1.2rem rgba(0, 0, 0, 0.72),
    inset 0 0 0.18rem rgba(255, 242, 187, 0.1);
}

.project-lower-screen--main {
  left: 10.373%;
  top: 13.577%;
  width: 71.829%;
  height: 54.307%;
}

.project-lower-screen--right {
  left: 83.727%;
  top: 42.92%;
  width: 11.209%;
  height: 36.204%;
}

.project-lower-screen--button {
  top: 74.307%;
  height: 12.993%;
}

.project-lower-screen--button-1 {
  left: 9.194%;
  width: 7.522%;
}

.project-lower-screen--button-2 {
  left: 19.223%;
  width: 8.063%;
}

.project-lower-screen--button-3 {
  left: 29.4%;
  width: 7.424%;
}

.project-lower-screen--button-4 {
  left: 38.987%;
  width: 7.67%;
}

.project-lower-screen--button-5 {
  left: 48.771%;
  width: 7.424%;
}

.project-lower-screen--button-long {
  left: 63.619%;
  width: 17.453%;
}

/* ------- Mobile lower panel ------- */
/* Mobile uses a different frame image (square-ish, two rows of buttons under a
   tall main screen). The screens/buttons reuse .project-lower-screen for their
   gradient + inset shadow, and these per-class rules supply the % positions
   measured off the mobile frame webp (1024x1168). */
.project-lower-screen--main-mb {
  left: 10.449%;
  top: 7.534%;
  width: 79.102%;
  height: 62.842%;
}

.project-lower-screen--button-mb-1 {
  left: 9.961%;
  top: 74.743%;
  width: 12.598%;
  height: 7.021%;
}

.project-lower-screen--button-mb-2 {
  left: 26.270%;
  top: 74.743%;
  width: 12.598%;
  height: 7.021%;
}

.project-lower-screen--button-mb-3 {
  left: 42.773%;
  top: 74.743%;
  width: 12.695%;
  height: 7.021%;
}

.project-lower-screen--button-mb-4 {
  left: 59.473%;
  top: 74.658%;
  width: 12.695%;
  height: 7.106%;
}

.project-lower-screen--button-mb-5 {
  left: 76.270%;
  top: 74.658%;
  width: 12.695%;
  height: 7.106%;
}

.project-lower-screen--button-mb-big-1 {
  left: 10.352%;
  top: 85.702%;
  width: 37.109%;
  height: 7.962%;
}

.project-lower-screen--button-mb-big-2 {
  left: 52.051%;
  top: 85.788%;
  width: 37.207%;
  height: 7.877%;
}

.project-panel-main {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: clamp(0.16rem, 0.3vw, 0.32rem);
  width: 100%;
  height: 100%;
  /* The lower panel is a small screen — keep the chrome thin so content gets
     the room. */
  padding: clamp(0.28rem, 0.55vw, 0.5rem) clamp(0.4rem, 0.85vw, 0.72rem);
}

/* Media is laid out as a row: the ALL/SS/VID button column sits flush against
   the left edge, the thumbnail grid takes the rest. No outer padding — each
   child owns its own insets. */
.project-panel-main--media {
  flex-direction: row;
  gap: 0;
  padding: 0;
}

/* Mobile panel has decorative corner pieces on the frame webp that overlap
   slightly into the screen area. The desktop variant lives inside a frame
   with thinner corner decals and can use very tight padding, but the
   mobile variant needs a bit more inner inset so labels in the corners
   (e.g. the TITLE row in STATS) don't clip under the decoration. */
.project-lower-panel-mb .project-panel-main {
  padding: clamp(0.5rem, 1.6cqi, 0.8rem) clamp(0.6rem, 1.8cqi, 0.95rem);
}

/* The mobile main screen is closer to square than the desktop variant's
   long-and-short one, so the IMG thumbnails can afford to be taller. The
   desktop rule keeps rows short to fit the squat screen; override here so
   the cqi-driven row height bumps up to a more square cell on mobile. */
.project-lower-panel-mb .project-panel-thumb-grid {
  grid-auto-rows: clamp(80px, 24cqi, 180px);
}

/* In the mobile panel the screen is taller than it is wide, so the media tabs
   run along the TOP instead of down the left edge. Padding inside the panel
   is otherwise so tight that there's no real outer gap to spend; each child
   owns its own insets, same as the desktop variant. */
.project-lower-panel-mb .project-panel-main--media {
  flex-direction: column;
}

.project-lower-panel-mb .project-panel-media-tabs {
  align-self: stretch;
  display: grid;
  grid-template-rows: none;
  grid-template-columns: repeat(3, 1fr);
}

.project-lower-panel-mb .project-panel-media-tab {
  /* Equal horizontal padding both sides; vertical padding stays tight because
     screen height is precious. The desktop variant trims the FIRST tab's top
     padding to dodge a decal on the panel-frame webp — the mobile frame has
     no such decal across the top of the tab row, so no override needed. */
  padding: clamp(0.16rem, 0.7cqi, 0.36rem) clamp(0.34rem, 1cqi, 0.7rem);
  /* Cancel the desktop pull-up that collapsed adjacent VERTICAL borders into
     one line; mobile lays them out horizontally so the trick doesn't apply. */
  margin-bottom: 0;
  margin-right: -1px;
}

.project-lower-panel-mb .project-panel-media-tab:last-child {
  margin-right: 0;
}

.project-lower-panel-mb .project-panel-media-tab:first-child {
  padding-top: clamp(0.16rem, 0.7cqi, 0.36rem);
}

.project-panel-main > .project-panel-thumb-grid,
.project-panel-main > .project-panel-stats,
.project-panel-main > .project-panel-desc-text,
.project-panel-main > .project-panel-links {
  flex: 1;
  min-height: 0;
}

.project-panel-main::after,
.project-cartridge-screen::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  background:
    radial-gradient(circle at 76% 18%, rgba(255, 255, 255, 0.07), transparent 22%),
    linear-gradient(180deg, rgba(255, 242, 187, 0.03), transparent 48%, rgba(0, 0, 0, 0.16));
  opacity: 0.6;
}

.project-panel-header {
  display: flex;
  align-items: baseline;
  gap: clamp(0.4rem, 0.8vw, 0.8rem);
  min-width: 0;
}

.project-panel-kicker,
.project-panel-meta,
.project-side-line {
  color: rgba(216, 208, 167, 0.58);
  font-family: var(--font-faded);
  letter-spacing: 0.04em;
}

.project-panel-kicker,
.project-panel-meta,
.project-side-line,
.project-panel-button {
  display: block;
  line-height: 1;
  white-space: nowrap;
}

.project-panel-title {
  margin: 0;
  overflow: hidden;
  color: rgba(255, 242, 187, 0.92);
  font-family: var(--font-title);
  /* Kept compact — the title is a one-line header, not the focus of the tab.
     The previous size ate a big slice of an already-small panel. */
  font-size: clamp(0.9rem, 1.15vw, 1.35rem);
  line-height: 1;
  font-weight: 400;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.project-panel-kicker {
  font-size: clamp(0.74rem, 0.78vw, 0.88rem);
}

.project-panel-summary {
  /* The DESC tab is just title + summary. Summary fills the remaining vertical
     space inside the main-display flex column. If the text overruns the
     available space, scroll — no clamping, no truncation. */
  margin: 0;
  flex: 1;
  min-height: 0;
  overflow: auto;
  color: rgba(216, 208, 167, 0.82);
  font-family: var(--font-faded);
  font-size: clamp(0.8rem, 0.9vw, 1.02rem);
  /* Bitcount is size-adjusted to 78%, so this stays fairly tight relative to
     the glyphs — enough without crowding the wrapped lines. */
  line-height: 0.92;
  scrollbar-width: thin;
  scrollbar-color: rgba(216, 208, 167, 0.18) transparent;
  padding-right: 0.2rem;
}

.project-panel-summary::-webkit-scrollbar {
  width: 4px;
}

.project-panel-summary::-webkit-scrollbar-thumb {
  background: rgba(216, 208, 167, 0.18);
}

.project-panel-desc-text {
  display: block;
  min-width: 0;
  min-height: 0;
  overflow: auto;
  font-family: var(--font-faded);
  scrollbar-width: thin;
  scrollbar-color: rgba(216, 208, 167, 0.18) transparent;
  padding-right: 0.2rem;
}

.project-panel-desc-text::-webkit-scrollbar {
  width: 4px;
}

.project-panel-desc-text::-webkit-scrollbar-thumb {
  background: rgba(216, 208, 167, 0.18);
}

.project-panel-summary {
  flex: initial;
  min-height: auto;
  overflow: visible;
  padding-right: 0;
  color: rgba(255, 242, 187, 0.86);
  line-height: 0.96;
}

.project-panel-desc-divider {
  display: block;
  height: 1px;
  margin: clamp(0.34rem, 0.74cqi, 0.66rem) 0;
  background:
    linear-gradient(90deg, rgba(216, 208, 167, 0), rgba(216, 208, 167, 0.34), rgba(127, 188, 195, 0.22), rgba(216, 208, 167, 0));
}

.project-panel-desc-copy {
  display: grid;
  gap: clamp(0.36rem, 0.7cqi, 0.62rem);
}

.project-panel-desc-copy p {
  margin: 0;
  color: rgba(216, 208, 167, 0.78);
  font-family: var(--font-faded);
  font-size: clamp(0.78rem, 0.86vw, 0.98rem);
  line-height: 1.02;
}

.project-panel-desc-text a {
  color: rgba(127, 188, 195, 0.95);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.12em;
}

.project-panel-desc-text a:hover,
.project-panel-desc-text a:focus-visible {
  color: rgba(255, 242, 187, 0.95);
  outline: none;
}

.project-panel-meta {
  font-size: clamp(0.72rem, 0.72vw, 0.84rem);
  color: rgba(170, 162, 124, 0.62);
}

.project-panel-thumb-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(clamp(96px, 20cqi, 180px), 1fr));
  /* Rows are deliberately a touch shorter than the grid's own height: one row
     nearly fills the space, and the next row peeks in just enough to signal
     "this scrolls". cqi tracks the panel width, which has a fixed aspect, so
     the peek stays consistent across viewport sizes. */
  grid-auto-rows: clamp(52px, 14.5cqi, 140px);
  gap: clamp(0.2rem, 0.5cqi, 0.5rem);
  flex: 1;
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  /* The media panel has no outer padding — the grid owns its own insets. */
  padding: clamp(0.26rem, 0.6cqi, 0.55rem);
  scrollbar-width: thin;
  scrollbar-color: rgba(216, 208, 167, 0.18) transparent;
}

.project-panel-thumb-grid::-webkit-scrollbar {
  width: 4px;
}

.project-panel-thumb-grid::-webkit-scrollbar-thumb {
  background: rgba(216, 208, 167, 0.18);
}

.project-panel-thumb {
  position: relative;
  padding: 0;
  overflow: hidden;
  background: #020302;
  border: 1px solid rgba(216, 208, 167, 0.14);
  cursor: pointer;
  transition: border-color 160ms ease, transform 160ms ease;
}

.project-panel-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(78%) brightness(82%) contrast(1.05);
  transition: filter 180ms ease;
}

.project-panel-thumb:hover,
.project-panel-thumb:focus-visible {
  border-color: rgba(255, 242, 187, 0.42);
  outline: none;
}

.project-panel-thumb:hover img,
.project-panel-thumb:focus-visible img {
  filter: saturate(95%) brightness(98%) contrast(1.04);
}

.project-panel-thumb.is-active {
  border-color: rgba(255, 242, 187, 0.72);
}

.project-panel-thumb.is-active img {
  filter: saturate(90%) brightness(92%) contrast(1.04);
}

/* MEDIA tab: a flush button column down the panel's left edge. The buttons
   stretch to fill the full panel height and collapse their borders into one
   shared-line stack. It's a flex item of the row panel, but lays its own
   buttons out as a grid: the panel height arrives through a chain of
   percentage heights, and flex-grow refused to distribute it (the buttons
   stayed content-sized and overflowed), whereas grid 1fr tracks distribute
   it reliably. */
.project-panel-media-tabs {
  flex: none;
  align-self: stretch;
  display: grid;
  grid-template-rows: repeat(3, 1fr);
}

.project-panel-media-tab {
  /* Grid item — its 1fr row sets the height. min-height:0 keeps the content's
     min-size from inflating the row; overflow:hidden clips gracefully if the
     label/count ever exceed the compact row. */
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.05rem;
  /* Compact: tight vertical padding so all three buttons fit the column height
     without clipping; tight horizontal padding keeps the column narrow. */
  padding: clamp(0.1rem, 0.7cqi, 0.5rem) clamp(0.34rem, 1cqi, 0.7rem);
  overflow: hidden;
  background: rgba(216, 208, 167, 0.06);
  border: 1px solid rgba(216, 208, 167, 0.16);
  /* Pull each button up by 1px so its top border lands on the previous
     button's bottom border — adjacent buttons share a single line. */
  margin-bottom: -1px;
  color: rgba(216, 208, 167, 0.62);
  cursor: pointer;
  transition: border-color 140ms ease, color 140ms ease, background 140ms ease;
}

.project-panel-media-tab:last-child {
  margin-bottom: 0;
}

/* The panel-frame webp has a decal over the screen's top-left corner that
   overlaps the top of the ALL button. Trim its top padding so the label still
   reads as centered within the part of the button that's actually visible. */
.project-panel-media-tab:first-child {
  padding-top: clamp(0.02rem, 0.2cqi, 0.16rem);
}

.project-panel-media-tab-label {
  font-family: var(--font-terminal);
  font-size: clamp(0.78rem, 2cqi, 1.3rem);
  letter-spacing: 0.06em;
  line-height: 1;
}

.project-panel-media-tab-count {
  font-family: var(--font-faded);
  font-size: clamp(0.62rem, 1.5cqi, 1rem);
  line-height: 1;
  color: rgba(216, 208, 167, 0.5);
}

.project-panel-media-tab:hover,
.project-panel-media-tab:focus-visible {
  /* Lift above neighbors so the collapsed border shows the full hover/active
     outline instead of being half-covered. */
  position: relative;
  z-index: 1;
  border-color: rgba(255, 242, 187, 0.42);
  color: rgba(255, 242, 187, 0.82);
  outline: none;
}

.project-panel-media-tab.is-active {
  position: relative;
  z-index: 1;
  background: rgba(255, 242, 187, 0.14);
  border-color: rgba(255, 242, 187, 0.5);
  color: rgba(255, 242, 187, 0.92);
}

.project-panel-media-tab.is-active .project-panel-media-tab-count {
  color: rgba(255, 242, 187, 0.7);
}

.project-panel-media-empty {
  flex: 1;
  display: grid;
  place-items: center;
  min-height: 0;
  color: rgba(170, 162, 124, 0.55);
  font-family: var(--font-faded);
  font-size: clamp(0.78rem, 0.8vw, 0.92rem);
  letter-spacing: 0.06em;
}

.project-panel-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.22rem clamp(0.6rem, 1.4vw, 1.6rem);
  align-content: start;
  min-height: 0;
  overflow: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(216, 208, 167, 0.18) transparent;
  padding-right: 0.2rem;
}

.project-panel-stats::-webkit-scrollbar {
  width: 4px;
}

.project-panel-stats::-webkit-scrollbar-thumb {
  background: rgba(216, 208, 167, 0.18);
}

.project-panel-stat-row {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.55rem;
  align-items: baseline;
  white-space: nowrap;
  overflow: hidden;
}

/* In STATS the data TYPE is the bright label and the data VALUE is the faded
   read-out — the field name is what the eye scans for. */
.project-panel-stat-label {
  color: rgba(255, 242, 187, 0.92);
  font-family: var(--font-terminal);
  font-size: clamp(0.7rem, 0.72vw, 0.82rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.project-panel-stat-value {
  color: rgba(216, 208, 167, 0.6);
  font-family: var(--font-faded);
  font-size: clamp(0.74rem, 0.78vw, 0.9rem);
  text-overflow: ellipsis;
  overflow: hidden;
}

.project-panel-links {
  display: grid;
  grid-template-columns: 1fr;
  /* No gap — links share borders into one continuous terminal-style list. */
  gap: 0;
  align-content: start;
  min-height: 0;
  overflow: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(216, 208, 167, 0.18) transparent;
  padding-right: 0.2rem;
}

.project-panel-links::-webkit-scrollbar {
  width: 4px;
}

.project-panel-links::-webkit-scrollbar-thumb {
  background: rgba(216, 208, 167, 0.18);
}

.project-panel-link {
  display: grid;
  grid-template-columns: minmax(60px, auto) minmax(0, 1fr);
  gap: 0.6rem;
  align-items: start;
  padding: clamp(0.22rem, 0.55cqi, 0.46rem) 0.5rem;
  text-decoration: none;
  color: rgba(216, 208, 167, 0.78);
  background: rgba(216, 208, 167, 0.04);
  border: 1px solid rgba(216, 208, 167, 0.16);
  /* Pull each row up 1px so its top border lands on the previous row's bottom
     border — the list reads as one bordered block, no doubled lines or gaps. */
  margin-bottom: -1px;
  transition: border-color 140ms ease, background 140ms ease;
}

.project-panel-link:last-child {
  margin-bottom: 0;
}

.project-panel-link:hover,
.project-panel-link:focus-visible {
  position: relative;
  z-index: 1;
  border-color: rgba(255, 242, 187, 0.46);
  background: rgba(255, 242, 187, 0.06);
  outline: none;
}

.project-panel-link-label {
  min-width: 0;
  font-family: var(--font-terminal);
  font-size: clamp(0.74rem, 0.78vw, 0.9rem);
  letter-spacing: 0.06em;
  line-height: 1.05;
  color: rgba(255, 242, 187, 0.92);
  overflow-wrap: anywhere;
}

.project-panel-link-note {
  min-width: 0;
  font-family: var(--font-faded);
  font-size: clamp(0.7rem, 0.72vw, 0.82rem);
  line-height: 1.05;
  color: rgba(216, 208, 167, 0.62);
  white-space: normal;
  overflow-wrap: anywhere;
}

.project-panel-blog-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  align-content: start;
  flex: 1;
  min-height: 0;
  overflow: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(216, 208, 167, 0.18) transparent;
  padding-right: 0.2rem;
}

.project-panel-blog-list::-webkit-scrollbar {
  width: 4px;
}

.project-panel-blog-list::-webkit-scrollbar-thumb {
  background: rgba(216, 208, 167, 0.18);
}

.project-panel-blog-post {
  display: grid;
  gap: 0.14rem;
  width: 100%;
  padding: clamp(0.24rem, 0.58cqi, 0.5rem) 0.5rem;
  margin-bottom: -1px;
  overflow: hidden;
  color: rgba(216, 208, 167, 0.76);
  text-align: left;
  background: rgba(216, 208, 167, 0.04);
  border: 1px solid rgba(216, 208, 167, 0.16);
  cursor: pointer;
  font: inherit;
  transition: border-color 140ms ease, background 140ms ease, color 140ms ease;
}

.project-panel-blog-post:last-child {
  margin-bottom: 0;
}

.project-panel-blog-post:hover,
.project-panel-blog-post:focus-visible {
  position: relative;
  z-index: 1;
  color: rgba(255, 242, 187, 0.9);
  background: rgba(255, 242, 187, 0.06);
  border-color: rgba(255, 242, 187, 0.46);
  outline: none;
}

.project-panel-blog-title {
  overflow: hidden;
  color: rgba(255, 242, 187, 0.92);
  font-family: var(--font-terminal);
  font-size: clamp(0.76rem, 0.8vw, 0.94rem);
  letter-spacing: 0.05em;
  line-height: 1;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.project-panel-blog-date {
  color: rgba(170, 162, 124, 0.66);
  font-family: var(--font-faded);
  font-size: clamp(0.66rem, 0.7vw, 0.8rem);
  line-height: 1;
}

.project-panel-blog-summary {
  display: -webkit-box;
  overflow: hidden;
  color: rgba(216, 208, 167, 0.64);
  font-family: var(--font-faded);
  font-size: clamp(0.7rem, 0.74vw, 0.86rem);
  line-height: 0.98;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.project-panel-placeholder {
  flex: 1;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 0.36rem;
  min-height: 0;
  text-align: center;
  padding: 0 12%;
}

.project-panel-placeholder-status {
  color: rgba(216, 208, 167, 0.5);
  font-family: var(--font-faded);
  font-size: clamp(0.72rem, 0.74vw, 0.84rem);
  letter-spacing: 0.08em;
}

.project-panel-placeholder-headline {
  margin: 0;
  color: rgba(255, 242, 187, 0.92);
  font-family: var(--font-title);
  font-size: clamp(1.2rem, 1.9vw, 2.2rem);
  letter-spacing: 0.02em;
}

.project-side-readout {
  position: relative;
  z-index: 1;
  display: grid;
  align-content: center;
  gap: 0.26rem;
  width: 100%;
  height: 100%;
  padding: 11% 13%;
}

.project-side-line {
  overflow: hidden;
  font-size: clamp(0.7rem, 0.68vw, 0.82rem);
  text-overflow: ellipsis;
}

.project-side-bar {
  display: block;
  height: 0.28rem;
  overflow: hidden;
  background: rgba(216, 208, 167, 0.12);
}

.project-side-bar::before {
  content: "";
  display: block;
  width: var(--project-side-fill, 62%);
  height: 100%;
  background: linear-gradient(90deg, rgba(127, 188, 195, 0.74), rgba(255, 242, 187, 0.72));
}

.project-lower-screen--button {
  padding: 0;
  background:
    radial-gradient(circle at 18% 12%, rgba(127, 188, 195, 0.13), transparent 34%),
    linear-gradient(180deg, rgba(14, 18, 15, 0.94), rgba(2, 3, 2, 0.98));
  border: 0;
  cursor: pointer;
  font: inherit;
  transition: filter 160ms ease;
}

.project-lower-screen--button:hover:not(:disabled),
.project-lower-screen--button:focus-visible {
  filter: brightness(1.18) saturate(1.08);
  outline: none;
}

.project-lower-screen--button:disabled {
  cursor: default;
  opacity: 0.55;
}

.project-lower-screen--button.is-active {
  filter: brightness(1.32) saturate(1.12);
}

.project-panel-button {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  padding: 0.08rem 0.24rem;
  overflow: hidden;
  color: rgba(216, 208, 167, 0.78);
  font-family: var(--font-terminal);
  /* Sized off the panel's container inline size so the label grows with the
     button instead of staying a tiny note in a wide chassis. The clamp keeps
     it sensible at the narrow + extreme-wide ends — but most of the time
     ~2.05 cqi is what's doing the work, matching what 'BACK TO HOME' (the
     longest label, in the widest button slot) can hold without clipping. */
  font-size: clamp(0.78rem, 2.05cqi, 1.45rem);
  letter-spacing: 0.04em;
  text-align: center;
  text-overflow: ellipsis;
}

.project-lower-screen--button.is-active .project-panel-button {
  color: rgba(255, 242, 187, 0.94);
}

.project-cartridge-rack {
  --rack-selected-y: 32%;
  position: absolute;
  z-index: 8;
  left: clamp(12px, 2.6vw, 56px);
  top: 1.5vh;
  height: clamp(620px, 112vh, 1480px);
  aspect-ratio: 439 / 1766;
  pointer-events: none;
  /* Rests fully below the visible UI and rides up into frame when opened.
     The rack stays opaque the entire time — never fades — so the cap appears
     to physically rise from below the holographic edge. */
  transform: translate3d(0, 102vh, 0);
  transform-origin: 50% 100%;
  transition: transform 760ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  will-change: transform;
}

.project-cartridge-tower,
.project-selected-frame {
  position: absolute;
  display: block;
  height: auto;
  pointer-events: none;
  user-select: none;
}

.project-cartridge-tower {
  z-index: 1;
  inset: 0;
  width: 100%;
}

.project-cartridge-viewport {
  position: absolute;
  z-index: 2;
  top: 5.889%;
  right: 0;
  bottom: 0;
  left: 0;
  overflow: hidden;
}

.project-cartridge-shadow {
  position: absolute;
  z-index: 3;
  left: 0;
  right: 0;
  top: 5.889%;
  height: 5.606%;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.95) 0%,
    rgba(0, 0, 0, 0.62) 38%,
    rgba(0, 0, 0, 0.28) 72%,
    rgba(0, 0, 0, 0) 100%
  );
}

.project-cartridge-track {
  position: absolute;
  inset: 0;
  transform: translate3d(0, var(--cartridge-track-offset, 0px), 0);
  transition: transform 680ms cubic-bezier(0.2, 0.82, 0.2, 1);
  will-change: transform;
}

.project-cartridge {
  position: absolute;
  left: 14.579%;
  width: 69.248%;
  aspect-ratio: 702 / 350;
  padding: 0;
  overflow: visible;
  color: rgba(216, 208, 167, 0.74);
  background: transparent;
  border: 0;
  cursor: pointer;
  font-family: var(--font-terminal);
  transform: translate3d(0, 0, 0);
  transition:
    filter 180ms ease,
    transform 180ms ease;
}

.project-cartridge:hover,
.project-cartridge:focus-visible {
  filter: brightness(1.12) saturate(1.05);
}

.project-cartridge:focus-visible {
  outline: 1px solid rgba(255, 242, 187, 0.62);
  outline-offset: 3px;
}

.project-cartridge.is-selected {
  filter: brightness(1.08) saturate(1.08);
}

.project-cartridge-screen,
.project-cartridge-plate,
.project-cartridge-shell {
  position: absolute;
}

.project-cartridge-screen {
  z-index: 1;
  left: 7.265%;
  top: 15.714%;
  width: 37.037%;
  height: 67.714%;
  overflow: hidden;
  background:
    radial-gradient(circle at 24% 10%, rgba(127, 188, 195, 0.12), transparent 34%),
    #020302;
}

.project-cartridge-screen img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(74%) brightness(72%) contrast(1.08);
}

.project-cartridge-shell {
  z-index: 2;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
  user-select: none;
}

.project-cartridge-plate {
  z-index: 3;
  left: 49.573%;
  top: 18.571%;
  display: grid;
  align-content: center;
  gap: 0.12rem;
  width: 41.311%;
  height: 61.714%;
  overflow: hidden;
  text-align: left;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.7);
}

.project-cartridge-title,
.project-cartridge-meta {
  display: block;
  overflow: hidden;
  line-height: 1;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.project-cartridge-title {
  color: rgba(248, 236, 188, 0.92);
  font-family: var(--font-title);
  font-size: clamp(0.78rem, 0.78vw, 1rem);
  letter-spacing: 0.02em;
}

.project-cartridge-meta {
  color: rgba(196, 184, 138, 0.78);
  font-family: var(--font-faded);
  font-size: clamp(0.66rem, 0.6vw, 0.74rem);
  letter-spacing: 0.06em;
}

.project-selected-frame {
  z-index: 4;
  top: var(--rack-selected-y);
  left: 50%;
  width: 100.42%;
  transform: translate3d(-50%, -50%, 0);
  filter: drop-shadow(0 0 0.48rem rgba(240, 162, 60, 0.12));
}

/* ------- BACK TO SCREEN (mobile only) ------- */
/* Lives on the cartridge "page" — visible only when the user has panned to
   the cartridge side. Replicates the .label-card aesthetic (blurred bg +
   wear mask + holographic corner stamps + scanlines + grain) so it reads
   as one of the home-page HUD labels rather than a generic button. Hidden
   on desktop. */
.project-back-to-screen {
  position: absolute;
  z-index: 8;
  display: none;
  align-items: center;
  gap: 0.62rem;
  padding: clamp(0.55rem, 1.8vw, 0.85rem) clamp(0.78rem, 2.4vw, 1.15rem);
  color: rgba(232, 225, 185, 0.88);
  font-family: var(--font-terminal);
  font-size: 1.04rem;
  letter-spacing: 0.06em;
  text-shadow: 0 0 6px rgba(216, 208, 167, 0.22);
  /* Pre-baked blurred copy of the page background — same image the label
     cards use. Size/position are driven by --label-bg-size/-x/-y, set by
     JS so the bg portion lines up with the underlying scene background.
     Pan offset is subtracted from bg-position-x so the bg stays anchored
     to the viewport as the button slides between pages. */
  background-image: url("../assets/backgrounds/background-blurred.jpg");
  background-size: var(--label-bg-size, 100vw 100vh);
  background-position:
    calc(var(--label-bg-x, 0px) - var(--project-mb-pan-x, 0px))
    var(--label-bg-y, 0px);
  background-repeat: no-repeat;
  border: 0;
  /* Home label cards use a side-notch clip-path, but that only works when
     the card is tall enough (~80px) for the side stamps to still show
     above/below the 22–78% notches. On a ~30px button the notches eat
     most of the vertical corner stamps and they look truncated next to
     the un-notched horizontal stamps. Keep the button rectangular and
     let the corner stamps read as full-length. */
  isolation: isolate;
  cursor: pointer;
  pointer-events: none;
  user-select: none;
  /* Resting pose is off-screen left; mobile open rules animate it in via the
     pan variable, identical timing/curve to the cartridge rack so the two
     read as a single panning camera move. */
  transform: translate3d(-100vw, 0, 0);
  transition:
    transform 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8),
    filter 160ms ease;
  will-change: transform;
  backface-visibility: hidden;
}

/* HUD corner stamps + side lines + scanlines, all masked by the surface
   wear texture so the holographic chrome looks weathered, on top of a
   nearly-opaque dark base that lets the blurred bg read through. */
.project-back-to-screen::before {
  content: "";
  position: absolute;
  z-index: 0;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(var(--hud-corner), var(--hud-corner)) left top / 1.25rem 2px no-repeat,
    linear-gradient(var(--hud-corner), var(--hud-corner)) left top / 2px 1.25rem no-repeat,
    linear-gradient(var(--hud-corner), var(--hud-corner)) right top / 1.25rem 2px no-repeat,
    linear-gradient(var(--hud-corner), var(--hud-corner)) right top / 2px 1.25rem no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) left bottom / 1.05rem 2px no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) left bottom / 2px 1.05rem no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) right bottom / 1.05rem 2px no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) right bottom / 2px 1.05rem no-repeat,
    linear-gradient(var(--hud-border), var(--hud-border)) left 1px top 1px / calc(100% - 2px) 1px no-repeat,
    linear-gradient(var(--hud-border), var(--hud-border)) left 1px bottom 1px / calc(100% - 2px) 1px no-repeat,
    linear-gradient(var(--hud-border), var(--hud-border)) left 1px top 1px / 1px calc(100% - 2px) no-repeat,
    linear-gradient(var(--hud-border), var(--hud-border)) right 1px top 1px / 1px calc(100% - 2px) no-repeat,
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 5px),
    rgba(4, 7, 6, 0.18);
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

/* Subtle grain highlight, same recipe as .label-card::after. */
.project-back-to-screen::after {
  content: "";
  position: absolute;
  z-index: 0;
  inset: 0;
  pointer-events: none;
  opacity: 0.16;
  background:
    repeating-linear-gradient(91deg, transparent 0 17px, rgba(255, 244, 194, 0.16) 18px, transparent 20px),
    radial-gradient(circle at 24% 31%, rgba(255, 244, 194, 0.18) 0 1px, transparent 2px),
    radial-gradient(circle at 79% 61%, rgba(0, 0, 0, 0.42) 0 1px, transparent 3px);
  background-size: 100% 100%, 19px 13px, 23px 17px;
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

.project-back-to-screen:hover,
.project-back-to-screen:focus-visible {
  filter: brightness(1.18) saturate(1.08);
  outline: none;
}

.project-back-to-screen-label {
  position: relative;
  z-index: 1;
  display: block;
  line-height: 1;
  white-space: nowrap;
}

/* Right-pointing arrow drawn purely with borders — no glyph, no svg, no extra
   asset. Matches the bright-amber/yellow HUD accent. The text-wear mask is
   applied to the whole element (border-area included) so the arrow shows
   the same weathered/holed-out texture the label and other HUD text do. */
.project-back-to-screen-arrow {
  position: relative;
  z-index: 1;
  display: block;
  width: 0;
  height: 0;
  border-top: 0.42rem solid transparent;
  border-bottom: 0.42rem solid transparent;
  border-left: 0.56rem solid rgba(255, 242, 187, 0.86);
  -webkit-mask-image: var(--text-wear-mask);
  mask-image: var(--text-wear-mask);
  -webkit-mask-position: var(--text-wear-x, 0px) var(--text-wear-y, 0px);
  mask-position: var(--text-wear-x, 0px) var(--text-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--text-wear-size);
  mask-size: var(--text-wear-size);
}

/* The bob is a continuous animation that translates the monitor a few pixels
   on Y. In open mode the rig is scaled ~2.4x, so the bob would visibly bounce
   the open-size monitor by ~25 px. The close transition holds the rig in
   open position for 480ms while the panel retracts — letting the bob jolt
   back to life during that window (or during the rig's travel home) is the
   kind of detail that breaks the "physical object" feel. Pause for the
   union of open + closing. JS removes .is-projects-closing once the close
   motion has settled. */
.scene.is-projects-open .project-bob,
.scene.is-projects-closing .project-bob,
.scene.is-blog-open .project-bob,
.scene.is-blog-closing .project-bob {
  animation-play-state: paused;
}

.scene.is-projects-open .project-plane {
  /* Same transform structure as the closed state, all angles zero — gives a
     clean rotational interpolation between rest pose and face-on. */
  transform: perspective(900px) rotateZ(0deg) rotateX(0deg) rotateY(0deg);
}

/* The plane's drop-shadow gradient fades with the plane's 3D rotation.
   Opacity transitions over the same 680ms curve as the plane transform,
   so the shadow eases away as the monitor pivots flat and eases back in
   as it returns to its tilted rest pose. The keyframe animation (gradient
   lift in sync with the bob) is paused under either class so the gradient
   doesn't drift relative to a static or invisible monitor. */
.scene.is-projects-open .project-plane::after {
  opacity: 0;
  animation-play-state: paused;
}

.scene.is-projects-closing .project-plane::after {
  animation-play-state: paused;
}

.scene.is-projects-staging .project-lower-panel {
  left: var(--project-panel-open-x);
  top: var(--project-panel-open-closed-y);
  visibility: hidden;
  transform: none;
  transition: none;
  will-change: auto;
  backface-visibility: visible;
}

.scene.is-projects-open .project-lower-panel {
  left: var(--project-panel-open-x);
  top: var(--project-panel-open-y);
  pointer-events: auto;
  visibility: visible;
  transform: none;
  will-change: auto;
  backface-visibility: visible;
  /* Panel only becomes visible AND starts sliding once the monitor has landed
     in place. With the rig's curve resolving its last few % at ~600ms, kick
     the reveal there — waiting the full 680ms reads as a glitchy pause. */
  transition:
    visibility 0s linear 600ms,
    top 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8) 600ms;
}

.scene.is-projects-closing .project-lower-panel {
  left: var(--project-panel-home-x);
  top: var(--project-panel-home-closed-y);
  visibility: hidden;
  transform: perspective(900px)
    rotateZ(14deg)
    rotateX(-8deg)
    rotateY(17deg)
    scale(var(--project-panel-home-scale));
  will-change: left, top, transform;
  transition:
    visibility 0s linear 680ms,
    left 680ms cubic-bezier(0.33, 0.2, 0.67, 0.8),
    top 680ms cubic-bezier(0.33, 0.2, 0.67, 0.8),
    transform 680ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
}

.scene.is-projects-open .project-cartridge-rack {
  pointer-events: auto;
  transform: translate3d(0, 0, 0);
  /* Tiny stagger so the rack starts rising a beat after the rig begins
     scaling — gives the rack its own rhythm during open without breaking
     coordination. The close path uses the base 480ms delay. */
  transition-delay: 80ms;
}

/* HUD elements slide toward their nearest holographic-frame edge. clip-path on
   .archive-stage means they disappear at the frame, not at the viewport edge.
   No opacity is involved — these are meant to feel like physical UI panels
   retracting into the edge of the holographic display.

   The 480ms transition-delay in the base rule is the close-side wait: when
   the open class comes off, every peripheral element waits for the panel to
   tuck behind the monitor (~480ms) before it begins traveling back. That
   gives the user one coherent "user is moving back to start position" beat
   instead of half the scene drifting home while the monitor sits frozen.
   The open-state rules below set transition-delay to 0 so the open path
   isn't affected — when the class is added, peripherals move immediately
   alongside the rig. */
.brand-hud,
.session-hud,
.hud-stack,
.bottom-hud {
  transition: transform 720ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  will-change: transform;
}
/* .label-card owns its own transition list lower in the file because JS also
   retunes left/top for the floating-label reflow. */

.scene.is-projects-open .brand-hud,
.scene.is-blog-open .brand-hud {
  /* Straight up, through the top frame edge. No diagonal. */
  transform: translateY(calc(-100% - var(--screen-frame-gap) * 2));
  pointer-events: none;
}

.scene.is-projects-open .session-hud,
.scene.is-blog-open .session-hud {
  /* Straight up, through the top frame edge. No diagonal. */
  transform: translateY(calc(-100% - var(--screen-frame-gap) * 2));
  pointer-events: none;
}

.scene.is-projects-open .hud-stack--left,
.scene.is-blog-open .hud-stack--left {
  transform: translateX(calc(-100% - var(--screen-frame-gap) * 2));
  pointer-events: none;
}

.scene.is-projects-open .hud-stack--right,
.scene.is-blog-open .hud-stack--right {
  transform: translateX(calc(100% + var(--screen-frame-gap) * 2));
  pointer-events: none;
}

.scene.is-projects-open .bottom-hud,
.scene.is-blog-open .bottom-hud {
  transform: translateY(calc(100% + var(--screen-frame-gap) * 2));
  pointer-events: none;
}

/* These labels are small HUD plates, so their exit should stay quiet: a quick
   vertical power-down, like the display surface losing scan height. */

.scene.is-projects-open .label-card.project-label,
.scene.is-projects-open .label-card.blog-label,
.scene.is-blog-open .label-card.project-label,
.scene.is-blog-open .label-card.blog-label {
  opacity: 0;
  transform: scaleY(0);
  transition:
    left 220ms ease,
    top 220ms ease,
    transform 180ms cubic-bezier(0.42, 0, 0.72, 0.18),
    opacity 80ms linear 100ms;
  pointer-events: none;
}

.scene.is-projects-closing .label-card.project-label,
.scene.is-projects-closing .label-card.blog-label,
.scene.is-blog-closing .label-card.project-label,
.scene.is-blog-closing .label-card.blog-label {
  opacity: 1;
  transform: scaleY(1);
  transition:
    left 220ms ease,
    top 220ms ease,
    transform 220ms cubic-bezier(0.18, 0.82, 0.24, 1) 460ms,
    opacity 100ms linear 460ms;
  pointer-events: none;
}

.blog-rig {
  position: absolute;
  z-index: 2;
  right: 26vw;
  bottom: clamp(155px, 23vh, 260px);
  width: var(--blog-rig-width, clamp(255px, 19.2vw, 430px));
  pointer-events: auto;
  transform-origin: 0 0;
  backface-visibility: hidden;
  /* This invisible sizing rig owns the layout math for the home position.
     The visible frame and screens live in .blog-frame-portal, so the
     close-up image can resize as a real box instead of being transform-scaled.

     The travel only needs to push the rig past the right edge of the
     holographic frame, where the archive-stage's clip-path takes over.
     The rig sits with its left edge at ~54vw natural, so ~50vw of travel
     clears it. Match the project rig's desktop 680ms travel so both home
     objects return to their resting positions on the same beat. */
  /* Blog rig slides at t=0 in both directions, alongside the rest of the
     scene's camera motion. */
  transition: transform 680ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  will-change: transform;
}

.blog-frame-portal {
  position: absolute;
  z-index: 3;
  right: 26vw;
  bottom: clamp(155px, 23vh, 260px);
  left: var(--blog-frame-open-left, var(--blog-frame-home-left, auto));
  top: var(--blog-frame-open-top, var(--blog-frame-home-top, auto));
  width: var(--blog-frame-open-width, var(--blog-frame-home-width, var(--blog-rig-width, clamp(255px, 19.2vw, 430px))));
  height: var(--blog-frame-open-height, var(--blog-frame-home-height, auto));
  aspect-ratio: 2583 / 9648;
  pointer-events: auto;
  transform: var(--blog-frame-home-transform, none);
  transform-origin: 0 0;
  backface-visibility: hidden;
  transition: transform 680ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  will-change: transform;
}

.blog-rig-swing {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 2583 / 9648;
  animation: blog-swing 11.5s ease-in-out infinite;
  transform-origin: 52% 0%;
  backface-visibility: hidden;
}

.blog-frame-swing {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 2583 / 9648;
  animation: blog-swing 11.5s ease-in-out infinite;
  transform-origin: 52% 0%;
  backface-visibility: hidden;
}

.blog-frame-piece {
  position: absolute;
  z-index: 2;
  display: block;
  max-width: none;
  height: auto;
  pointer-events: none;
  user-select: none;
  backface-visibility: hidden;
}

.blog-frame-piece--upper-cable {
  left: 50.1742%;
  top: 0;
  width: 8.982%;
}

.blog-frame-piece--lower {
  left: 0;
  top: 53.8246%;
  width: 100%;
}

.scene.is-projects-open .blog-rig {
  transform: translate3d(50vw, 0, 0);
  pointer-events: none;
}

.scene.is-projects-open .blog-frame-portal {
  transform: translate3d(50vw, 0, 0);
}

.scene.is-blog-open .blog-rig {
  transform: var(--blog-rig-transform, none);
}

.scene.is-blog-open .blog-frame-portal {
  right: auto;
  bottom: auto;
  pointer-events: none;
  transform: none;
}

.scene.is-blog-reader-visible .blog-rig {
  pointer-events: none;
}

.scene.is-blog-closing .blog-rig {
  transform: none;
}

.scene.is-blog-closing .blog-frame-portal {
  right: auto;
  bottom: auto;
  transform: var(--blog-frame-home-transform, none);
}

/* Swing pauses under both classes for the same reason the bob does —
   the rig shouldn't be visibly swaying while it's traveling on/off
   screen, and it shouldn't lurch back to swinging the instant the
   close click fires. */
.scene.is-projects-open .blog-rig-swing,
.scene.is-projects-closing .blog-rig-swing,
.scene.is-projects-open .blog-frame-swing,
.scene.is-projects-closing .blog-frame-swing {
  animation-play-state: paused;
}

.scene.is-blog-open .blog-rig-swing,
.scene.is-blog-open .blog-frame-swing {
  animation: none;
  transform: rotateZ(0deg);
  transition: transform 680ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
}

.scene.is-blog-closing .blog-rig-swing,
.scene.is-blog-closing .blog-frame-swing {
  animation: none;
  transform: rotateZ(-2deg);
  transition: transform 680ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
}

@keyframes blog-swing {
  0%,
  100% {
    transform: rotateZ(-2deg);
  }

  50% {
    transform: rotateZ(-0.8deg);
  }
}

.blog-display-layer {
  position: absolute;
  z-index: 1;
  inset: 0;
}

.blog-reader-portal {
  position: absolute;
  z-index: 1;
  inset: 0;
  pointer-events: none;
}

.blog-panel {
  position: absolute;
  display: block;
  overflow: hidden;
  padding: 2%;
  color: var(--screen-green);
  background:
    radial-gradient(circle at 18% 0, rgba(127, 188, 195, 0.14), transparent 34%),
    var(--screen-black);
  text-decoration: none;
  container-type: inline-size;
  isolation: isolate;
  cursor: pointer;
}

.scene.is-blog-reader-visible .blog-panel {
  cursor: default;
  pointer-events: none;
}

.scene.is-blog-reader-visible .blog-panel--top-main {
  background: transparent;
}

.scene.is-blog-reader-visible .blog-panel--top-main .blog-panel-content {
  visibility: hidden;
}

.scene.is-blog-reader-visible .blog-panel--top-left {
  clip-path: inset(0 57% 0 0);
}

.scene.is-blog-reader-visible .blog-panel--bottom-left {
  clip-path: inset(0 48% 0 0);
}

.scene.is-blog-reader-visible .blog-panel--top-right {
  clip-path: inset(0 0 0 62%);
}

.scene.is-blog-reader-visible .blog-panel--bottom-right {
  clip-path: inset(0 0 0 59%);
}

.scene.is-blog-closing .blog-panel--top-main,
.scene.is-blog-closing .blog-panel--bottom-main {
  cursor: default;
}

.blog-panel-content {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  gap: 3px;
  width: 100%;
  height: 100%;
}

.screen-sweep {
  position: absolute;
  z-index: 3;
  top: 0;
  left: -2%;
  width: 104%;
  height: 72%;
  --screen-sweep-exit: 138.9%;
  pointer-events: none;
  opacity: 0;
  transform: translate3d(0, -100%, 0);
  background:
    linear-gradient(
      180deg,
      transparent 0%,
      rgba(193, 255, 218, 0) 12%,
      rgba(193, 255, 218, 0.006) 34%,
      rgba(193, 255, 218, 0.018) 55%,
      rgba(219, 255, 225, 0.042) 73%,
      rgba(240, 255, 222, 0.092) 88%,
      rgba(248, 255, 224, 0.18) calc(100% - 2px),
      rgba(255, 255, 234, 0.34) calc(100% - 1px),
      rgba(120, 240, 218, 0.08) 100%
    );
  will-change: transform, opacity;
}

.screen-sweep.is-sweeping {
  animation: screen-sweep var(--screen-sweep-duration, 6.4s) linear forwards;
}

.blog-panel--side .screen-sweep {
  height: 80%;
  --screen-sweep-exit: 125%;
  opacity: 0;
}

@keyframes screen-sweep {
  0% {
    opacity: 1;
    transform: translate3d(0, -100%, 0);
  }

  100% {
    opacity: 1;
    transform: translate3d(0, var(--screen-sweep-exit), 0);
  }
}

.blog-panel--primary {
  z-index: 2;
  padding: 2%;
}

.blog-panel--side {
  z-index: 1;
  padding: 0;
  color: rgba(183, 200, 173, 0.76);
}

.blog-panel--side .blog-panel-content {
  position: absolute;
  top: 0;
  left: var(--side-content-left, 0%);
  width: var(--side-content-width, 100%);
  padding: var(--side-content-padding, 4%);
  background:
    radial-gradient(circle at 18% 0, rgba(127, 188, 195, 0.14), transparent 34%),
    var(--screen-black);
}

/* Blog panel coordinates are measured on the 2583x9648 source image.
   Side panels intentionally use the FULL screen rectangles, including the
   portions covered by the center monitors, so screen fill remains visible
   through transparent frame/cable gaps. */
.blog-panel--top-main {
  /* x:761 y:6743 w:1251 h:823 */
  left: 29.461866%;
  top: 69.890133%;
  width: 48.432056%;
  height: 8.530265%;
}

.blog-panel--bottom-main {
  /* x:686 y:8107 w:1320 h:878 */
  left: 26.558266%;
  top: 84.027778%;
  width: 51.103368%;
  height: 9.100332%;
}

.blog-panel--top-left {
  /* x:283 y:7090 w:1125 h:740 */
  left: 10.956252%;
  top: 73.486733%;
  width: 43.554007%;
  height: 7.669983%;
  --side-content-padding: 4%;
}

.blog-panel--bottom-left {
  /* x:142 y:8441 w:1041 h:685 */
  left: 5.497484%;
  top: 87.489635%;
  width: 40.301974%;
  height: 7.099917%;
  --side-content-padding: 4%;
}

.blog-panel--top-right {
  /* top-right x:2352 y:7215, w:886 h:583 */
  left: 56.755710%;
  top: 74.782338%;
  width: 34.301200%;
  height: 6.042703%;
}

.blog-panel--bottom-right {
  /* top-right x:2425 y:8421, w:1014 h:667 */
  left: 54.626403%;
  top: 87.282338%;
  width: 39.256678%;
  height: 6.913350%;
}

.blog-date,
.blog-copy {
  position: relative;
  z-index: 1;
  display: block;
  overflow: hidden;
  font-size: var(--blog-fit-font-size, 1rem);
  /* Blog-monitor text is its own visual register (green CRT), not part of the
     bright/faded HUD system — give it the new face per the design pass. */
  font-family: var(--font-faded);
}

.blog-date {
  white-space: nowrap;
  line-height: 1;
}

.blog-copy {
  width: 100%;
  height: 100%;
  line-height: 1.16;
  white-space: normal;
  word-break: normal;
  overflow-wrap: normal;
  hyphens: none;
}

.blog-reader-overlay {
  position: absolute;
  z-index: 4;
  --blog-reader-screen-clip: inset(0);
  --blog-reader-screen-transform: none;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  visibility: hidden;
  overflow: hidden;
  color: rgba(216, 208, 167, 0.84);
  background:
    radial-gradient(circle at 82% 8%, rgba(127, 188, 195, 0.12), transparent 26%),
    linear-gradient(180deg, #080c0a, var(--screen-black));
  box-shadow:
    inset 0 0 0 1px rgba(216, 208, 167, 0.18),
    inset 0 0 42px rgba(0, 0, 0, 0.72),
    0 0 18px rgba(127, 188, 195, 0.08);
  opacity: 1;
  pointer-events: none;
  clip-path: var(--blog-reader-screen-clip);
  transition: visibility 0s linear 120ms;
}

.scene.is-blog-reader-visible .blog-reader-overlay {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  transition: visibility 0s linear;
}

.scene.is-blog-closing .blog-reader-overlay {
  visibility: hidden;
  opacity: 1;
  pointer-events: none;
  transition: none;
}

.scene.is-blog-open .blog-reader-overlay[aria-hidden="true"],
.scene.is-blog-closing .blog-reader-overlay[aria-hidden="true"] {
  visibility: hidden;
  opacity: 1;
  pointer-events: none;
  transition: none;
}

.blog-reader-overlay > .blog-reader,
.blog-reader-overlay > .blog-lightbox {
  opacity: 0;
  transition: opacity 120ms linear;
}

.scene.is-blog-reader-visible .blog-reader-overlay > .blog-reader,
.scene.is-blog-reader-visible .blog-reader-overlay > .blog-lightbox {
  opacity: 1;
}

.scene.is-blog-closing .blog-reader-overlay > .blog-reader,
.scene.is-blog-closing .blog-reader-overlay > .blog-lightbox,
.scene.is-blog-open .blog-reader-overlay[aria-hidden="true"] > .blog-reader,
.scene.is-blog-open .blog-reader-overlay[aria-hidden="true"] > .blog-lightbox,
.scene.is-blog-closing .blog-reader-overlay[aria-hidden="true"] > .blog-reader,
.scene.is-blog-closing .blog-reader-overlay[aria-hidden="true"] > .blog-lightbox {
  opacity: 0;
  transition: none;
}

.blog-reader-overlay::after {
  content: "";
  position: absolute;
  z-index: 3;
  inset: 0;
  pointer-events: none;
  background:
    repeating-linear-gradient(0deg, rgba(255, 246, 199, 0.08) 0 1px, transparent 1px 4px),
    radial-gradient(circle at 78% 18%, rgba(255, 255, 255, 0.06), transparent 22%);
  opacity: 0.42;
}

.blog-reader-overlay--bottom > .blog-reader,
.blog-reader-overlay--bottom > .blog-lightbox,
.blog-reader-overlay--bottom::after {
  transform: var(--blog-reader-screen-transform);
  transform-origin: 0 0;
}

.blog-reader {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(10.5rem, 24%) minmax(0, 1fr);
  width: 100%;
  height: 100%;
  min-height: 0;
  font-family: var(--font-faded);
}

.blog-reader-list {
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  min-width: 0;
  min-height: 0;
  border-right: 1px solid rgba(216, 208, 167, 0.16);
  background:
    linear-gradient(90deg, rgba(216, 208, 167, 0.06), rgba(216, 208, 167, 0.015)),
    rgba(2, 3, 2, 0.3);
}

.blog-reader-posts {
  display: grid;
  align-content: start;
  min-height: 0;
  overflow-y: auto;
  padding: 0 0 clamp(0.55rem, 1vw, 0.9rem);
  scrollbar-width: thin;
  scrollbar-color: rgba(216, 208, 167, 0.22) transparent;
}

.blog-reader-posts::-webkit-scrollbar,
.blog-reader-article::-webkit-scrollbar,
.blog-reader-thumbs::-webkit-scrollbar {
  width: 4px;
  height: 4px;
}

.blog-reader-posts::-webkit-scrollbar-thumb,
.blog-reader-article::-webkit-scrollbar-thumb,
.blog-reader-thumbs::-webkit-scrollbar-thumb {
  background: rgba(216, 208, 167, 0.22);
}

.blog-reader-post {
  display: grid;
  gap: 0.18rem;
  width: 100%;
  padding: clamp(0.42rem, 0.7vw, 0.64rem) clamp(0.42rem, 0.8vw, 0.7rem);
  margin-bottom: -1px;
  overflow: hidden;
  color: rgba(216, 208, 167, 0.74);
  text-align: left;
  background: rgba(216, 208, 167, 0.045);
  border: 1px solid rgba(216, 208, 167, 0.14);
  border-right: 0;
  border-left: 0;
  cursor: pointer;
  font: inherit;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}

.blog-reader-post:last-child {
  margin-bottom: 0;
}

.blog-reader-post:hover,
.blog-reader-post:focus-visible,
.blog-reader-post.is-active {
  position: relative;
  z-index: 1;
  color: rgba(255, 242, 187, 0.9);
  background: rgba(255, 242, 187, 0.075);
  border-color: rgba(255, 242, 187, 0.44);
  outline: none;
}

.blog-reader-post-date,
.blog-reader-post-title,
.blog-reader-home,
.blog-lightbox-back {
  display: block;
  line-height: 1;
  white-space: nowrap;
}

.blog-reader-post-date {
  color: rgba(170, 162, 124, 0.72);
  font-size: clamp(0.72rem, 0.82vw, 0.92rem);
}

.blog-reader-post-title {
  overflow: hidden;
  color: inherit;
  font-family: var(--font-terminal);
  font-size: clamp(0.9rem, 1.05vw, 1.18rem);
  text-overflow: ellipsis;
}

.blog-reader-home {
  width: 100%;
  padding: clamp(0.62rem, 1vw, 0.9rem);
  color: rgba(255, 242, 187, 0.84);
  text-align: left;
  background: transparent;
  border: 0;
  border-top: 1px solid rgba(216, 208, 167, 0.16);
  cursor: pointer;
  font-family: var(--font-terminal);
  font-size: clamp(0.88rem, 1.02vw, 1.14rem);
  letter-spacing: 0.06em;
}

.blog-reader-home:hover,
.blog-reader-home:focus-visible,
.blog-lightbox-back:hover,
.blog-lightbox-back:focus-visible {
  color: rgba(255, 242, 187, 1);
  outline: none;
}

.blog-reader-article {
  height: 100%;
  overflow-y: auto;
  min-width: 0;
  min-height: 0;
  scrollbar-width: thin;
  scrollbar-color: rgba(216, 208, 167, 0.22) transparent;
}

.blog-reader-media {
  display: grid;
  grid-template-rows: minmax(0, 1fr) clamp(3.4rem, 5.8vw, 5rem);
  gap: clamp(0.42rem, 0.72vw, 0.7rem);
  height: 52%;
  min-height: 12rem;
  padding: clamp(0.62rem, 1vw, 0.92rem);
  border-bottom: 1px solid rgba(216, 208, 167, 0.14);
}

.blog-reader-hero {
  position: relative;
  min-width: 0;
  min-height: 0;
  padding: 0;
  overflow: hidden;
  background: #020302;
  border: 1px solid rgba(216, 208, 167, 0.16);
  cursor: pointer;
}

.blog-reader-hero:focus-visible {
  border-color: rgba(255, 242, 187, 0.58);
  outline: none;
}

.blog-reader-hero img,
.blog-reader-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(74%) brightness(82%) contrast(1.05);
}

.blog-reader-thumbs {
  display: flex;
  gap: clamp(0.28rem, 0.52vw, 0.48rem);
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: 0.2rem;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  scrollbar-color: rgba(216, 208, 167, 0.22) transparent;
}

.blog-reader-thumb {
  flex: 0 0 clamp(5.4rem, 9vw, 8.6rem);
  min-width: 0;
  height: 100%;
  padding: 0;
  overflow: hidden;
  background: #020302;
  border: 1px solid rgba(216, 208, 167, 0.14);
  cursor: pointer;
  scroll-snap-align: center;
}

.blog-reader-thumb:hover,
.blog-reader-thumb:focus-visible,
.blog-reader-thumb.is-active {
  border-color: rgba(255, 242, 187, 0.62);
  outline: none;
}

.blog-reader-copy {
  min-height: 0;
  padding: clamp(0.7rem, 1.1vw, 1rem) clamp(0.82rem, 1.35vw, 1.24rem);
}

.blog-reader-date {
  display: block;
  margin-bottom: 0.28rem;
  color: rgba(170, 162, 124, 0.72);
  font-size: clamp(0.76rem, 0.82vw, 0.94rem);
  line-height: 1;
}

.blog-reader-title {
  margin: 0 0 clamp(0.44rem, 0.72vw, 0.72rem);
  color: rgba(255, 242, 187, 0.92);
  font-family: var(--font-title);
  font-size: clamp(1.35rem, 2vw, 2.2rem);
  font-weight: 400;
  line-height: 0.92;
}

.blog-reader-copy p {
  margin: 0 0 0.62rem;
  color: rgba(216, 208, 167, 0.76);
  font-size: clamp(0.86rem, 0.98vw, 1.1rem);
  line-height: 1.08;
}

.blog-reader-copy p a {
  color: rgba(127, 188, 195, 0.95);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.12em;
}

.blog-reader-copy p a:hover,
.blog-reader-copy p a:focus-visible {
  color: rgba(255, 242, 187, 0.95);
  outline: none;
}

.blog-reader-project-links {
  display: grid;
  gap: 0.38rem;
  margin-top: clamp(0.9rem, 1.4vw, 1.35rem);
  padding-top: clamp(0.5rem, 0.9vw, 0.8rem);
  border-top: 1px solid rgba(216, 208, 167, 0.18);
}

.blog-reader-project-links-label {
  display: block;
  color: rgba(255, 242, 187, 0.82);
  font-family: var(--font-terminal);
  font-size: clamp(0.78rem, 0.86vw, 0.98rem);
  letter-spacing: 0.07em;
  line-height: 1;
}

.blog-reader-project-links-list {
  display: grid;
  gap: 0;
}

.blog-reader-project-link {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.7rem;
  align-items: baseline;
  padding: clamp(0.34rem, 0.64vw, 0.55rem) 0.58rem;
  margin-bottom: -1px;
  color: rgba(216, 208, 167, 0.76);
  text-decoration: none;
  background: rgba(216, 208, 167, 0.045);
  border: 1px solid rgba(216, 208, 167, 0.15);
  transition: border-color 140ms ease, background 140ms ease, color 140ms ease;
}

.blog-reader-project-link:last-child {
  margin-bottom: 0;
}

.blog-reader-project-link:hover,
.blog-reader-project-link:focus-visible {
  position: relative;
  z-index: 1;
  color: rgba(255, 242, 187, 0.92);
  background: rgba(255, 242, 187, 0.06);
  border-color: rgba(255, 242, 187, 0.42);
  outline: none;
}

.blog-reader-project-link-title,
.blog-reader-project-link-meta {
  display: block;
  min-width: 0;
  line-height: 1;
  white-space: nowrap;
}

.blog-reader-project-link-title {
  overflow: hidden;
  color: inherit;
  font-family: var(--font-terminal);
  font-size: clamp(0.82rem, 0.94vw, 1.04rem);
  letter-spacing: 0.06em;
  text-overflow: ellipsis;
}

.blog-reader-project-link-meta {
  color: rgba(170, 162, 124, 0.68);
  font-size: clamp(0.68rem, 0.78vw, 0.9rem);
}

.blog-reader-empty {
  display: grid;
  place-items: center;
  min-height: 0;
  color: rgba(170, 162, 124, 0.62);
  font-size: clamp(0.86rem, 0.96vw, 1rem);
  letter-spacing: 0.06em;
}

.blog-lightbox {
  position: absolute;
  z-index: 8;
  inset: 0;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  place-items: center;
  background: rgba(2, 3, 2, 0.99);
  cursor: pointer;
}

.blog-lightbox[hidden] {
  display: none;
}

.blog-lightbox img {
  display: block;
  max-width: 100%;
  max-height: calc(100% - 3rem);
  object-fit: contain;
  cursor: pointer;
}

.blog-lightbox-footer {
  display: flex;
  justify-content: center;
  gap: clamp(0.8rem, 1.5vw, 1.4rem);
  width: 100%;
  padding: 0.7rem 1rem 0.9rem;
  text-align: center;
}

.blog-lightbox-back {
  padding: 0.16rem 0.35rem;
  margin: 0;
  color: rgba(255, 242, 187, 0.84);
  background: transparent;
  border: 0;
  cursor: pointer;
  font-family: var(--font-terminal);
  font-size: 1.12rem;
  letter-spacing: 0.06em;
}

.is-viewport-image-lightbox-open {
  overflow: hidden;
}

.viewport-image-lightbox {
  position: fixed;
  z-index: 100;
  inset: 0;
  display: grid;
  place-items: center;
  padding: clamp(0.5rem, 1.6vw, 1.6rem);
  background: #020302;
  cursor: zoom-out;
}

.viewport-image-lightbox[hidden] {
  display: none;
}

.viewport-image-lightbox img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  cursor: zoom-out;
}

.label-card {
  position: absolute;
  /* Above project-zone (z:3) and blog-zone (z:2) so the labels sit on
     top of every rig — they're meant to read as holographic UI floating
     right in front of the player. The frame ornamentation
     (.archive-stage::before z:6) still draws over them so they stay
     INSIDE the holographic frame visually. */
  z-index: 5;
  display: grid;
  gap: 0.48rem;
  width: 12.2rem;
  min-height: 5.1rem;
  padding: 1rem 1.12rem;
  pointer-events: none;
  color: rgba(232, 225, 185, 0.88);
  /* Pre-baked blur of the background image, used as a static fill so the cards
     read like backdrop-filter: blur(6px) without the per-frame GPU readback.
     `background-attachment: fixed` can't be used here because .label-card has
     `transform` and `will-change: transform`, which make the element its own
     containing block and silently degrade `fixed` to `local` — the whole image
     would scale to cover each card. Instead, alignLabelBackgroundFills() in
     homepage.js computes per-card --label-bg-size/--label-bg-x/--label-bg-y so
     the visible window through each card lines up with the underlying
     .scene::after background (which uses center / cover). */
  background-image: url("../assets/backgrounds/background-blurred.jpg");
  background-size: var(--label-bg-size, 100vw 100vh);
  background-position: var(--label-bg-x, 0px) var(--label-bg-y, 0px);
  background-repeat: no-repeat;
  border: 0;
  isolation: isolate;
  opacity: 1;
  transform: scaleY(1);
  transform-origin: 50% 50%;
  transition:
    left 220ms ease,
    top 220ms ease,
    transform 220ms cubic-bezier(0.18, 0.82, 0.24, 1),
    opacity 100ms linear;
  will-change: transform;
}

.label-card::before {
  content: "";
  position: absolute;
  z-index: 0;
  inset: 0;
  pointer-events: none;
  opacity: 1;
  background:
    linear-gradient(var(--hud-corner), var(--hud-corner)) left top / 1.25rem 2px no-repeat,
    linear-gradient(var(--hud-corner), var(--hud-corner)) left top / 2px 1.25rem no-repeat,
    linear-gradient(var(--hud-corner), var(--hud-corner)) right top / 1.25rem 2px no-repeat,
    linear-gradient(var(--hud-corner), var(--hud-corner)) right top / 2px 1.25rem no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) left bottom / 1.05rem 2px no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) left bottom / 2px 1.05rem no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) right bottom / 1.05rem 2px no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) right bottom / 2px 1.05rem no-repeat,
    linear-gradient(var(--hud-border), var(--hud-border)) left 1px top 1px / calc(100% - 2px) 1px no-repeat,
    linear-gradient(var(--hud-border), var(--hud-border)) left 1px bottom 1px / calc(100% - 2px) 1px no-repeat,
    linear-gradient(var(--hud-border), var(--hud-border)) left 1px top 1px / 1px calc(100% - 2px) no-repeat,
    linear-gradient(var(--hud-border), var(--hud-border)) right 1px top 1px / 1px calc(100% - 2px) no-repeat,
    linear-gradient(90deg, transparent 0 12px, rgba(232, 225, 185, 0.34) 13px, transparent 14px),
    linear-gradient(180deg, transparent 0 9px, rgba(232, 225, 185, 0.28) 10px, transparent 11px),
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 5px),
    radial-gradient(circle at 15% 20%, rgba(216, 208, 167, 0.16) 0 1px, transparent 2px),
    radial-gradient(circle at 76% 64%, rgba(216, 208, 167, 0.12) 0 1px, transparent 2px),
    repeating-linear-gradient(96deg, transparent 0 14px, rgba(216, 208, 167, 0.05) 15px, transparent 17px),
    rgba(4, 7, 6, 0.18);
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

.label-card::after,
.hud-panel::after,
.bottom-hud::after {
  content: "";
  position: absolute;
  z-index: 0;
  inset: 0;
  pointer-events: none;
  opacity: 0.16;
  background:
    repeating-linear-gradient(91deg, transparent 0 17px, rgba(255, 244, 194, 0.16) 18px, transparent 20px),
    radial-gradient(circle at 24% 31%, rgba(255, 244, 194, 0.18) 0 1px, transparent 2px),
    radial-gradient(circle at 79% 61%, rgba(0, 0, 0, 0.42) 0 1px, transparent 3px);
  background-size: 100% 100%, 19px 13px, 23px 17px;
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

.label-card .label-title {
  position: relative;
  font-size: 1.58rem;
  z-index: 1;
}

/* Pointer-nub that sticks out from one edge of the label and points
   toward the screen the label is for. Purely visual — its absolutely
   positioned outside-the-box geometry is invisible to JS layout (it
   doesn't extend the label's getBoundingClientRect), so it never enters
   the placement scoring. JS sets one of the directional modifier
   classes below to pick which edge the nub is on. */
.label-card-arrow {
  position: absolute;
  z-index: 2;
  width: 0;
  height: 0;
  margin: 0;
  padding: 0;
  pointer-events: none;
  /* Hidden until JS picks a side. */
  display: none;
  /* Weathered like the rest of the HUD chrome — JS gives each instance
     its own --text-wear-x/-y offset via offsetWeatheringMasks(), so
     adjacent nubs don't tile identically. */
  -webkit-mask-image: var(--text-wear-mask);
  mask-image: var(--text-wear-mask);
  -webkit-mask-position: var(--text-wear-x, 0px) var(--text-wear-y, 0px);
  mask-position: var(--text-wear-x, 0px) var(--text-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--text-wear-size);
  mask-size: var(--text-wear-size);
}

/* The triangle is drawn purely with CSS borders. The "pointing" side has
   the colored border (matching --hud-border, the same colour the
   label's outer frame line uses), the perpendicular sides are
   transparent so the result reads as an isoceles triangle. The base
   offset (5px instead of the 6px depth) shifts the nub 1px inward so
   its flat side lands on the label's visible inner border line — which
   is itself drawn 1px inside the element edge (see .label-card::before
   gradients), so a -depth offset would leave a 1px gap. The element is
   absolutely-positioned with width/height: 0, so neither the position
   shift nor the border-driven triangle affects the label's
   getBoundingClientRect — placement scoring stays nub-agnostic. */
.label-card-arrow.label-card-arrow--top {
  display: block;
  top: -5px;
  left: 50%;
  transform: translateX(-50%);
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
  border-bottom: 6px solid var(--hud-border);
}

.label-card-arrow.label-card-arrow--bottom {
  display: block;
  bottom: -5px;
  left: 50%;
  transform: translateX(-50%);
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
  border-top: 6px solid var(--hud-border);
}

.label-card-arrow.label-card-arrow--left {
  display: block;
  top: 50%;
  left: -5px;
  transform: translateY(-50%);
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
  border-right: 6px solid var(--hud-border);
}

.label-card-arrow.label-card-arrow--right {
  display: block;
  top: 50%;
  right: -5px;
  transform: translateY(-50%);
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
  border-left: 6px solid var(--hud-border);
}

.label-card span {
  position: relative;
  font-size: 1.26rem;
  line-height: 1.28;
  z-index: 1;
}

.label-card .text-muted {
  font-size: 1.1rem;
  line-height: 0.95;
}

.system-readout span,
.session-hud span,
.session-hud .readout-value,
.brand-lockup p,
.label-card .label-title,
.label-card span,
.hud-panel h2,
.hud-panel p,
.hud-panel span,
.bottom-hud span,
.bottom-hud .hud-value,
.project-back-to-screen-label {
  display: inline-block;
  position: relative;
  z-index: 1;
  padding-left: 1px;
  margin-left: -1px;
  color: transparent;
  background:
    linear-gradient(
      180deg,
      var(--text-gradient-top, rgba(250, 239, 190, 0.88)),
      var(--text-gradient-bottom, rgba(175, 167, 131, 0.62))
    ),
    radial-gradient(circle at 18% 44%, transparent 0 2px, var(--text-fleck, rgba(255, 246, 201, 0.26)) 3px, transparent 5px),
    repeating-linear-gradient(90deg, var(--text-scanline, rgba(255, 255, 255, 0.16)) 0 1px, transparent 1px 7px);
  /* The text gradient tile is one line tall (1lh) and repeats down the block,
     so every line gets the full top→bottom fade instead of the last line of a
     multi-line element washing out. The fleck/scanline layers keep their own
     sizes. */
  background-size: 100% 1lh, 31px 19px, 9px 100%;
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  -webkit-mask-image: var(--text-wear-mask);
  mask-image: var(--text-wear-mask);
  -webkit-mask-position: var(--text-wear-x, 0px) var(--text-wear-y, 0px);
  mask-position: var(--text-wear-x, 0px) var(--text-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--text-wear-size);
  mask-size: var(--text-wear-size);
}

.text-muted {
  /* Bitcount reads dimmer than Jersey did at the same alpha, so the muted
     gradient is brightened to compensate (top fully opaque, bottom lifted). */
  --text-gradient-top: rgba(250, 239, 190, 1);
  --text-gradient-bottom: rgba(175, 167, 131, 0.5);
  --text-fleck: rgba(255, 246, 201, 0.08);
  --text-scanline: rgba(255, 255, 255, 0.04);
  font-family: var(--font-faded);
  text-shadow: 0 0 4px rgba(216, 208, 167, 0.06);
}

/* Exception: the brand sub-line is faded text, but it reads better sharing
   the Jersey 10 face with the VRCODE wordmark directly above it — and since
   it's not Bitcount, it keeps the original (dimmer) muted gradient. */
.brand-lockup p.text-muted {
  --text-gradient-top: rgba(250, 239, 190, 0.5);
  --text-gradient-bottom: rgba(175, 167, 131, 0.4);
  font-family: var(--font-terminal);
}

.project-label {
  top: 45.4vh;
  left: 25.8vw;
}

.blog-label {
  top: 39vh;
  left: 74vw;
  width: 11.8rem;
}

.hud-stack {
  position: absolute;
  display: grid;
  gap: 1.8rem;
  width: 9.4rem;
  color: rgba(216, 208, 167, 0.62);
}

.hud-stack--left {
  top: 27vh;
  left: calc(var(--screen-frame-gap) * 2);
}

.hud-stack--right {
  top: 28vh;
  right: calc(var(--screen-frame-gap) * 2);
  width: 7.6rem;
}

.hud-panel {
  position: relative;
  min-height: 5.4rem;
  padding: 0.72rem 0.86rem;
  background: transparent;
  border: 0;
  isolation: isolate;
}

.hud-panel::before,
.bottom-hud::before {
  content: "";
  position: absolute;
  z-index: 0;
  inset: 0;
  pointer-events: none;
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
}

.hud-panel::before {
  background:
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) left top / 1rem 2px no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) left top / 2px 1rem no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) right top / 1rem 2px no-repeat,
    linear-gradient(var(--hud-corner-soft), var(--hud-corner-soft)) right top / 2px 1rem no-repeat,
    linear-gradient(rgba(255, 242, 187, 0.38), rgba(255, 242, 187, 0.38)) left bottom / 0.85rem 2px no-repeat,
    linear-gradient(rgba(255, 242, 187, 0.38), rgba(255, 242, 187, 0.38)) left bottom / 2px 0.85rem no-repeat,
    linear-gradient(rgba(255, 242, 187, 0.38), rgba(255, 242, 187, 0.38)) right bottom / 0.85rem 2px no-repeat,
    linear-gradient(rgba(255, 242, 187, 0.38), rgba(255, 242, 187, 0.38)) right bottom / 2px 0.85rem no-repeat,
    linear-gradient(var(--hud-panel-border), var(--hud-panel-border)) left 1px top 1px / calc(100% - 2px) 1px no-repeat,
    linear-gradient(var(--hud-panel-border), var(--hud-panel-border)) left 1px bottom 1px / calc(100% - 2px) 1px no-repeat,
    linear-gradient(var(--hud-panel-border), var(--hud-panel-border)) left 1px top 1px / 1px calc(100% - 2px) no-repeat,
    linear-gradient(var(--hud-panel-border), var(--hud-panel-border)) right 1px top 1px / 1px calc(100% - 2px) no-repeat,
    radial-gradient(circle at 7% 13%, rgba(216, 208, 167, 0.12) 0 1px, transparent 2px),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.03) 0 1px, transparent 1px 8px),
    rgba(5, 8, 7, 0.22);
}

.hud-panel h2 {
  margin: 0 0 0.72rem -1px;
  color: rgba(232, 225, 185, 0.74);
  font-size: 0.94rem;
  font-weight: 400;
}

.hud-panel p,
.hud-panel span {
  /* Bitcount is size-adjusted to 78%, so a 1.3 line-height + 0.18rem margins
     left a full glyph-height of dead air between stacked readout lines. Pull
     both in tight — 0.8 line-height clears the 78%-scaled glyphs comfortably. */
  margin: 0.1rem 0 0.1rem -1px;
  font-size: 0.94rem;
  line-height: 0.8;
}

/* The shared gradient rule above sets display:inline-block, which parks each
   stacked <p> readout in the panel's (much taller, inherited) line box — that
   was the real source of the "almost a whole line between rows" gap. Block
   flow lets the <p>'s own 0.8 line-height + collapsed margins set the rhythm. */
.hud-panel p {
  display: block;
}

.packet-log-line {
  min-width: 5.2rem;
  white-space: nowrap;
}

.packet-log-char {
  display: inline-block;
  white-space: pre;
}

.power-draw,
.memory-map,
.bar-readout,
.data-stream-bus {
  position: relative;
  z-index: 1;
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

.hud-panel--power-draw {
  min-height: 6.25rem;
}

.power-draw {
  width: 100%;
  height: 3.45rem;
  margin: 0.24rem 0 0.34rem;
  overflow: hidden;
  border-top: 1px solid rgba(216, 208, 167, 0.14);
  border-bottom: 1px solid rgba(216, 208, 167, 0.18);
}

.power-draw--wattmeter {
  --power-draw-coil-alpha: 0.34;
  --power-draw-coil-shift: 0;
  --power-draw-pivot-alpha: 0.34;
  --power-draw-plate-alpha: 0.12;
  background:
    radial-gradient(ellipse at 50% 76%, rgba(255, 242, 187, var(--power-draw-plate-alpha)) 0 18%, transparent 42%),
    linear-gradient(90deg, rgba(216, 208, 167, 0.08), transparent 14%, transparent 86%, rgba(216, 208, 167, 0.07)),
    repeating-linear-gradient(0deg, rgba(216, 208, 167, 0.035) 0 1px, transparent 1px 0.42rem),
    repeating-linear-gradient(90deg, rgba(216, 208, 167, 0.032) 0 1px, transparent 1px 0.58rem),
    rgba(4, 7, 6, 0.18);
}

.power-draw-wattmeter {
  position: absolute;
  inset: 0.1rem 0.12rem -0.02rem;
  width: calc(100% - 0.24rem);
  height: calc(100% - 0.08rem);
  overflow: visible;
}

.power-draw-plate,
.power-draw-dial-arc,
.power-draw-tick,
.power-draw-contact,
.power-draw-coil,
.power-draw-needle {
  vector-effect: non-scaling-stroke;
}

.power-draw-plate {
  fill: rgba(255, 242, 187, var(--power-draw-plate-alpha, 0.12));
  stroke: rgba(216, 208, 167, 0.14);
  stroke-width: 0.8;
}

.power-draw-dial-arc {
  fill: none;
  stroke-linecap: square;
}

.power-draw-dial-arc--base {
  stroke: rgba(216, 208, 167, 0.2);
  stroke-width: 1;
}

.power-draw-dial-arc--scale {
  stroke: rgba(255, 242, 187, 0.18);
  stroke-dasharray: 2.5 3;
  stroke-width: 1.2;
}

.power-draw-tick {
  stroke: rgba(255, 242, 187, 0.62);
  stroke-linecap: square;
  stroke-width: 0.85;
}

.power-draw-tick--major {
  stroke-width: 1.15;
}

.power-draw-contact {
  fill: none;
  stroke: rgba(216, 208, 167, 0.18);
  stroke-width: 0.95;
}

.power-draw-coil {
  fill: none;
  stroke: rgba(255, 242, 187, var(--power-draw-coil-alpha, 0.34));
  stroke-dasharray: 1.9 2.4;
  stroke-dashoffset: var(--power-draw-coil-shift, 0);
  stroke-linecap: square;
  stroke-width: 1.15;
}

.power-draw-needle {
  stroke: rgba(255, 242, 187, 0.78);
  stroke-linecap: square;
  stroke-width: 1;
}

.power-draw-needle--back {
  stroke: rgba(0, 0, 0, 0.42);
  stroke-width: 2.2;
  filter: none;
}

.power-draw-pivot {
  stroke: rgba(255, 242, 187, var(--power-draw-pivot-alpha, 0.34));
}

.power-draw-pivot--outer {
  fill: rgba(2, 5, 5, 0.48);
  stroke-width: 1;
}

.power-draw-pivot--inner {
  fill: rgba(255, 242, 187, var(--power-draw-pivot-alpha, 0.34));
  stroke-width: 0.5;
}

.hud-panel--power-draw .power-draw-readout {
  display: inline-grid;
  grid-template-columns: var(--power-draw-value-width, 3ch) auto;
  align-items: baseline;
  margin-top: 0;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.hud-panel--power-draw .power-draw-readout > span,
.hud-panel--power-draw .power-draw-slot-measure {
  padding-left: 0;
  margin-left: 0;
  font-size: inherit;
  line-height: inherit;
}

.hud-panel--power-draw .power-draw-value-number {
  width: var(--power-draw-value-width, auto);
  text-align: left;
}

.hud-panel--power-draw .power-draw-slot-measure {
  position: absolute;
  left: -9999px;
  width: auto;
  pointer-events: none;
  visibility: hidden;
  white-space: nowrap;
}

.hud-panel--memory-map {
  min-height: 7.25rem;
}

.memory-map {
  position: relative;
  width: 100%;
  height: 4.78rem;
  margin: 0.22rem 0 0.38rem;
  overflow: hidden;
  background:
    radial-gradient(circle at 18% 26%, rgba(255, 242, 187, 0.12) 0 1px, transparent 2px),
    radial-gradient(circle at 74% 66%, rgba(255, 242, 187, 0.1) 0 1px, transparent 2px),
    linear-gradient(140deg, rgba(216, 208, 167, 0.08), transparent 34%, transparent 68%, rgba(216, 208, 167, 0.06)),
    repeating-linear-gradient(0deg, rgba(216, 208, 167, 0.035) 0 1px, transparent 1px 0.48rem),
    repeating-linear-gradient(90deg, rgba(216, 208, 167, 0.04) 0 1px, transparent 1px 0.54rem),
    rgba(4, 7, 6, 0.18);
  border-top: 1px solid rgba(216, 208, 167, 0.14);
  border-bottom: 1px solid rgba(216, 208, 167, 0.18);
}

.memory-map-canvas {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.memory-map::before,
.memory-map::after {
  content: "";
  position: absolute;
  inset: 0.22rem;
  pointer-events: none;
}

.memory-map::before {
  z-index: 2;
  background:
    linear-gradient(90deg, transparent 0 24%, rgba(216, 208, 167, 0.12) 24.5% 25.5%, transparent 26% 49%, rgba(216, 208, 167, 0.1) 49.5% 50.5%, transparent 51% 74%, rgba(216, 208, 167, 0.12) 74.5% 75.5%, transparent 76%),
    linear-gradient(0deg, transparent 0 32%, rgba(216, 208, 167, 0.1) 32.5% 33.5%, transparent 34% 66%, rgba(216, 208, 167, 0.09) 66.5% 67.5%, transparent 68%);
}

.memory-map::after {
  z-index: 5;
  background:
    linear-gradient(180deg, rgba(4, 7, 6, 0.26), transparent 18%, transparent 82%, rgba(4, 7, 6, 0.32)),
    linear-gradient(90deg, rgba(4, 7, 6, 0.22), transparent 18%, transparent 82%, rgba(4, 7, 6, 0.2));
}

.memory-map-route {
  position: absolute;
  inset: 0.22rem;
  z-index: 4;
  width: calc(100% - 0.44rem);
  height: calc(100% - 0.44rem);
  overflow: visible;
  pointer-events: none;
}

.memory-map-route-line,
.memory-map-route-echo {
  fill: none;
  vector-effect: non-scaling-stroke;
}

.memory-map-route-echo {
  stroke: rgba(216, 208, 167, 0.16);
  stroke-dasharray: 2 4;
  stroke-width: 1;
}

.memory-map-route-line {
  stroke: rgba(255, 242, 187, 0.58);
  stroke-dasharray: 1.6 1.15;
  stroke-linecap: square;
  stroke-linejoin: round;
  stroke-width: 1.18;
  animation: memory-map-route-flow 2.6s linear infinite;
}

.memory-map-cursor {
  fill: rgba(255, 242, 187, 0.9);
  filter: drop-shadow(0 0 0.2rem rgba(255, 242, 187, 0.4));
  animation: memory-map-cursor-pulse 1.35s ease-in-out infinite;
}

.memory-map-readout {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 0.04rem;
}

.hud-panel .memory-map-readout span {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.08;
  white-space: nowrap;
}

@keyframes memory-map-route-flow {
  to {
    stroke-dashoffset: -2.75;
  }
}

@keyframes memory-map-cursor-pulse {
  0%,
  100% {
    opacity: 0.72;
  }

  50% {
    opacity: 1;
  }
}

.bar-readout {
  width: 5.8rem;
  height: 1.65rem;
  margin: 0.32rem 0 0.2rem;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  align-items: end;
  gap: 0.18rem;
  overflow: hidden;
  padding: 0.14rem 0.12rem 0.12rem;
  background:
    repeating-linear-gradient(0deg, rgba(216, 208, 167, 0.06) 0 1px, transparent 1px 6px),
    repeating-linear-gradient(90deg, transparent 0 8px, rgba(216, 208, 167, 0.08) 9px),
    rgba(4, 7, 6, 0.16);
  border-bottom: 1px solid rgba(216, 208, 167, 0.2);
}

.link-carrier {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  height: 100%;
  background:
    repeating-linear-gradient(0deg, rgba(216, 208, 167, 0.12) 0 1px, transparent 1px 4px),
    rgba(216, 208, 167, 0.04);
}

.link-carrier::before,
.link-carrier::after {
  content: "";
  position: absolute;
  right: 0;
  left: 0;
  bottom: 0;
  pointer-events: none;
}

.link-carrier::before {
  top: 45%;
  border-top: 1px solid rgba(216, 208, 167, 0.14);
}

.link-carrier::after {
  height: var(--link-carrier-fill, 45%);
  background:
    repeating-linear-gradient(0deg, rgba(255, 242, 187, 0.58) 0 2px, rgba(255, 242, 187, 0.18) 2px 4px, transparent 4px 5px),
    linear-gradient(180deg, rgba(255, 242, 187, 0.08), rgba(216, 208, 167, 0.38));
  opacity: var(--link-carrier-alpha, 0.7);
  transition:
    height 520ms cubic-bezier(0.24, 0.74, 0.3, 1),
    opacity 520ms ease;
}

.data-stream {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 0.42rem;
  width: 5.85rem;
}

.data-stream-bus {
  display: grid;
  gap: 0.17rem;
  height: 4.85rem;
  overflow: hidden;
  padding: 0.34rem 0.28rem;
  background:
    linear-gradient(90deg, rgba(216, 208, 167, 0.1), transparent 13%, transparent 87%, rgba(216, 208, 167, 0.09)),
    repeating-linear-gradient(0deg, transparent 0 0.56rem, rgba(216, 208, 167, 0.08) 0.57rem 0.62rem),
    repeating-linear-gradient(90deg, rgba(216, 208, 167, 0.055) 0 1px, transparent 1px 0.58rem),
    rgba(4, 7, 6, 0.2);
  border-top: 1px solid rgba(216, 208, 167, 0.14);
  border-bottom: 1px solid rgba(216, 208, 167, 0.18);
}

.data-stream-bus::before,
.data-stream-bus::after {
  content: "";
  position: absolute;
  top: 0.28rem;
  bottom: 0.28rem;
  z-index: 2;
  width: 1px;
  pointer-events: none;
  background: rgba(216, 208, 167, 0.22);
  box-shadow: 0 0 0.22rem rgba(216, 208, 167, 0.12);
}

.data-stream-bus::before {
  left: 0.26rem;
}

.data-stream-bus::after {
  right: 0.26rem;
}

.data-stream-lane {
  position: relative;
  display: grid;
  grid-template-columns: repeat(10, minmax(0, 1fr));
  align-items: center;
  gap: 1px;
  min-height: 0.44rem;
}

.data-stream-lane::before {
  content: "";
  position: absolute;
  right: 0;
  left: 0;
  top: 50%;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(90deg, rgba(216, 208, 167, 0.34), rgba(216, 208, 167, 0.08) 18%, rgba(216, 208, 167, 0.08) 82%, rgba(216, 208, 167, 0.28));
}

.data-stream-lane.is-sync::after {
  content: "";
  position: absolute;
  z-index: 3;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  pointer-events: none;
  background: rgba(255, 242, 187, 0.56);
  box-shadow: 0 0 0.22rem rgba(255, 242, 187, 0.36);
}

.data-stream-cell {
  position: relative;
  z-index: 1;
  display: block;
  min-width: 0;
  height: 0.32rem;
  background: rgba(216, 208, 167, 0.1);
  opacity: var(--data-cell-alpha, 0.2);
  transform: scaleX(var(--data-cell-scale, 0.38));
  transition:
    opacity 180ms ease,
    transform 180ms cubic-bezier(0.24, 0.74, 0.28, 1),
    background-color 180ms ease,
    box-shadow 180ms ease;
}

/* Eight discrete energy tiers. Each holds the (alpha, scale) the original
   continuous formula produced at energy = N/7, so the cell still breathes
   across the same value range, just snapped to 8 stops. The 180ms ease on
   opacity/transform above hides the stepping. JS only has to swap one
   class per cell per tick instead of writing --data-cell-alpha and
   --data-cell-scale every change. */
.data-stream-cell.is-l0 { --data-cell-alpha: 0.16; --data-cell-scale: 0.34; }
.data-stream-cell.is-l1 { --data-cell-alpha: 0.28; --data-cell-scale: 0.43; }
.data-stream-cell.is-l2 { --data-cell-alpha: 0.39; --data-cell-scale: 0.53; }
.data-stream-cell.is-l3 { --data-cell-alpha: 0.51; --data-cell-scale: 0.62; }
.data-stream-cell.is-l4 { --data-cell-alpha: 0.63; --data-cell-scale: 0.72; }
.data-stream-cell.is-l5 { --data-cell-alpha: 0.75; --data-cell-scale: 0.81; }
.data-stream-cell.is-l6 { --data-cell-alpha: 0.86; --data-cell-scale: 0.91; }
.data-stream-cell.is-l7 { --data-cell-alpha: 0.98; --data-cell-scale: 1.00; }

.data-stream-cell.is-tail {
  background: rgba(216, 208, 167, 0.28);
}

.data-stream-cell.is-active {
  background: rgba(255, 242, 187, 0.78);
  box-shadow: 0 0 0.24rem rgba(255, 242, 187, 0.34);
}

.data-stream-cell.is-head {
  background: rgba(255, 247, 201, 0.95);
  box-shadow: 0 0 0.3rem rgba(255, 242, 187, 0.48);
}

.data-stream-readouts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.04rem 0.28rem;
}

.hud-panel .data-stream-readouts > span {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1;
  white-space: nowrap;
}

.hud-panel .data-stream-readouts > span:first-child {
  grid-column: 1 / -1;
}

.hud-panel .data-stream-rate {
  display: inline-grid;
  grid-template-columns: auto var(--data-stream-rate-value-width, 4ch) auto;
  align-items: baseline;
  justify-self: start;
  column-gap: 0.14em;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.hud-panel .data-stream-rate > span,
.hud-panel .data-stream-rate-slot-measure {
  padding-left: 0;
  margin-left: 0;
  font-size: inherit;
  line-height: inherit;
}

.hud-panel .data-stream-rate-value {
  width: var(--data-stream-rate-value-width, auto);
  text-align: left;
}

.hud-panel .data-stream-rate-slot-measure {
  position: absolute;
  left: -9999px;
  width: auto;
  pointer-events: none;
  visibility: hidden;
  white-space: nowrap;
}

.core-temp {
  --core-temp-readout-value-width: 4ch;
  --core-temp-channel-width: 2.45rem;
  --core-temp-channel-gap: 0.32rem;
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(var(--core-temp-count, 1), var(--core-temp-channel-width));
  align-items: start;
  justify-items: start;
  justify-content: space-between;
  column-gap: var(--core-temp-channel-gap);
  gap: 0.18rem;
  width: 100%;
  padding: 0;
  margin: 0;
}

.core-temp-channel {
  display: grid;
  grid-template-columns: 100%;
  justify-items: center;
  gap: 0.16rem;
  width: var(--core-temp-channel-width);
  min-width: 0;
}

/* `display: grid` above wins over the UA-default `[hidden] { display: none }`.
   Without this re-affirmation, JS-toggled `channel.element.hidden = true`
   leaves the channel rendering — and the leftover channel wraps onto a
   second grid row once the array narrows past the channel count. */
.core-temp-channel[hidden] {
  display: none;
}

.core-temp-diode {
  position: relative;
  z-index: 1;
  width: 2rem;
  aspect-ratio: 1;
  box-sizing: border-box;
  overflow: hidden;
  border: 1px solid rgba(216, 208, 167, 0.18);
  border-radius: 50%;
  background: transparent;
  box-shadow:
    inset 0 0 0.32rem rgba(4, 7, 6, 0.72),
    0 0 0.24rem rgba(255, 242, 187, var(--core-temp-shell-glow, 0.08));
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

.bottom-hud .core-temp-readout {
  display: inline-grid;
  grid-template-columns: var(--core-temp-readout-value-width, 4ch) auto;
  align-items: baseline;
  justify-content: center;
  column-gap: 2px;
  margin: 0;
  width: 100%;
  font-size: 0.86rem;
  line-height: 1;
  text-align: center;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.bottom-hud .core-temp-readout > span,
.bottom-hud .core-temp-readout-slot-measure {
  padding-left: 0;
  margin-left: 0;
  font-size: inherit;
  line-height: inherit;
}

.bottom-hud .core-temp-readout-value {
  width: var(--core-temp-readout-value-width, 4ch);
  text-align: left;
}

.bottom-hud .core-temp-readout-slot-measure {
  position: absolute;
  left: -9999px;
  width: auto;
  pointer-events: none;
  visibility: hidden;
  white-space: nowrap;
}

.memory-usage {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 0.18rem;
  width: 100%;
  padding: 0;
  margin: 0;
}

.memory-bank-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-auto-rows: 1fr;
  gap: 0;
  width: 100%;
  box-sizing: border-box;
  height: 2rem;
  padding: 0.08rem 0.2rem;
  overflow: hidden;
  background:
    linear-gradient(180deg, rgba(216, 208, 167, 0.08), transparent 48%, rgba(216, 208, 167, 0.045)),
    repeating-linear-gradient(90deg, rgba(216, 208, 167, 0.055) 0 1px, transparent 1px 0.54rem),
    rgba(4, 7, 6, 0.2);
  border-top: 1px solid rgba(216, 208, 167, 0.14);
  border-bottom: 1px solid rgba(216, 208, 167, 0.18);
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

.memory-bank-grid::after {
  content: "";
  position: absolute;
  inset: 0.08rem 0.2rem;
  z-index: 3;
  pointer-events: none;
  background:
    linear-gradient(90deg, transparent 0 24%, rgba(216, 208, 167, 0.11) 24.5% 25.5%, transparent 26% 49%, rgba(216, 208, 167, 0.1) 49.5% 50.5%, transparent 51% 74%, rgba(216, 208, 167, 0.11) 74.5% 75.5%, transparent 76%),
    linear-gradient(180deg, rgba(4, 7, 6, 0.22), transparent 26%, transparent 74%, rgba(4, 7, 6, 0.28));
}

.memory-bank-row {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 0.9rem 1fr;
  align-items: center;
  gap: 0.22rem;
  min-height: 0;
}

.bottom-hud .memory-bank-label {
  margin: 0;
  font-size: 0.5rem;
  line-height: 1;
  letter-spacing: 0.06em;
}

.memory-bank-track {
  position: relative;
  height: 0.28rem;
  overflow: hidden;
  background:
    repeating-linear-gradient(90deg, rgba(216, 208, 167, 0.1) 0 1px, transparent 1px 0.34rem),
    rgba(216, 208, 167, 0.055);
  border-left: 1px solid rgba(216, 208, 167, 0.18);
  border-right: 1px solid rgba(216, 208, 167, 0.12);
}

.memory-bank-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--memory-bank-fill, 26%);
  background:
    linear-gradient(180deg, rgba(255, 242, 187, 0.48), rgba(216, 208, 167, 0.24)),
    repeating-linear-gradient(90deg, rgba(255, 242, 187, 0.2) 0 2px, transparent 2px 5px);
  box-shadow: 0 0 0.2rem rgba(255, 242, 187, 0.12);
}

.memory-bank-cursor {
  position: absolute;
  top: -0.04rem;
  bottom: -0.04rem;
  width: 1px;
  background: rgba(255, 242, 187, 0.82);
  box-shadow: 0 0 0.24rem rgba(255, 242, 187, 0.4);
  opacity: var(--memory-bank-cursor-alpha, 0.35);
  transform: translateX(-50%);
  /* Position scans 0->100% on the compositor; per-bank duration and
     starting phase (negative delay) come from JS at setup so different
     banks scan at slightly different speeds. */
  animation: memory-bank-cursor-scan var(--memory-bank-cursor-duration, 5.4s) linear infinite;
  animation-delay: var(--memory-bank-cursor-delay, 0s);
}

@keyframes memory-bank-cursor-scan {
  from { left: 0%; }
  to   { left: 100%; }
}

.memory-bank-row.is-memory-hot .memory-bank-fill {
  background:
    linear-gradient(180deg, rgba(255, 242, 187, 0.7), rgba(216, 208, 167, 0.3)),
    repeating-linear-gradient(90deg, rgba(255, 242, 187, 0.24) 0 2px, transparent 2px 5px);
  box-shadow: 0 0 0.34rem rgba(255, 242, 187, 0.24);
}

.memory-usage-readouts {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 0.34rem;
}

.bottom-hud .memory-usage-readouts .hud-value {
  margin: 0;
  font-size: 0.96rem;
  line-height: 1;
  white-space: nowrap;
}

.bottom-hud .memory-usage-readout {
  display: inline-grid;
  grid-template-columns: var(--memory-used-value-width, 4ch) auto auto auto auto;
  align-items: baseline;
  justify-self: start;
  column-gap: 0.22em;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.bottom-hud .memory-usage-readout > span,
.bottom-hud .memory-usage-slot-measure {
  padding-left: 0;
  margin-left: 0;
  font-size: inherit;
  line-height: inherit;
}

.bottom-hud .memory-usage-used-value {
  width: var(--memory-used-value-width, auto);
  text-align: left;
}

.bottom-hud .memory-usage-slot-measure {
  position: absolute;
  left: -9999px;
  width: auto;
  pointer-events: none;
  visibility: hidden;
  white-space: nowrap;
}

.bottom-hud .memory-usage-percent {
  min-width: 2.4rem;
  text-align: right;
}

.cpu-load {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 0.18rem;
  width: 100%;
  padding: 0;
  margin: 0;
}

.cpu-load-scope {
  position: relative;
  z-index: 1;
  width: 100%;
  box-sizing: border-box;
  height: 2rem;
  overflow: hidden;
  background:
    linear-gradient(180deg, rgba(216, 208, 167, 0.08), transparent 44%, rgba(216, 208, 167, 0.04)),
    repeating-linear-gradient(90deg, rgba(216, 208, 167, 0.06) 0 1px, transparent 1px 0.54rem),
    repeating-linear-gradient(0deg, rgba(216, 208, 167, 0.05) 0 1px, transparent 1px 0.42rem),
    rgba(4, 7, 6, 0.2);
  border-top: 1px solid rgba(216, 208, 167, 0.14);
  border-bottom: 1px solid rgba(216, 208, 167, 0.18);
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

.cpu-load-scope::after {
  content: "";
  position: absolute;
  top: 0.22rem;
  bottom: 0.22rem;
  right: 0.28rem;
  z-index: 3;
  width: 1px;
  pointer-events: none;
  background: rgba(255, 242, 187, 0.34);
  box-shadow: 0 0 0.22rem rgba(255, 242, 187, 0.16);
}

.cpu-load-scope svg {
  position: absolute;
  inset: 0.16rem 0.18rem;
  z-index: 2;
  width: calc(100% - 0.36rem);
  height: calc(100% - 0.32rem);
  overflow: visible;
}

.cpu-load-threshold,
.cpu-load-area,
.cpu-load-trace {
  vector-effect: non-scaling-stroke;
}

.cpu-load-threshold {
  fill: none;
  stroke: rgba(216, 208, 167, 0.18);
  stroke-dasharray: 2 3;
  stroke-width: 1;
}

.cpu-load-area {
  fill: rgba(216, 208, 167, 0.12);
}

.cpu-load-trace {
  fill: none;
  stroke: rgba(255, 242, 187, 0.72);
  stroke-linecap: square;
  stroke-linejoin: round;
  stroke-width: 1.15;
}

.cpu-load-head {
  fill: rgba(255, 242, 187, 0.92);
  opacity: 0.92;
}

.bottom-hud .cpu-load-readout {
  margin: 0;
  font-size: 1rem;
  line-height: 1;
}

.net-io {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 0.18rem;
  width: 100%;
  padding: 0;
  margin: 0;
}

.net-io-scope {
  position: relative;
  z-index: 1;
  width: 100%;
  box-sizing: border-box;
  height: 2rem;
  overflow: hidden;
  background:
    linear-gradient(180deg, rgba(216, 208, 167, 0.08), transparent 42%, rgba(216, 208, 167, 0.04)),
    repeating-linear-gradient(90deg, rgba(216, 208, 167, 0.07) 0 1px, transparent 1px 0.58rem),
    repeating-linear-gradient(0deg, rgba(216, 208, 167, 0.05) 0 1px, transparent 1px 0.42rem),
    rgba(4, 7, 6, 0.2);
  border-top: 1px solid rgba(216, 208, 167, 0.15);
  border-bottom: 1px solid rgba(216, 208, 167, 0.18);
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

.net-io-scope::before,
.net-io-scope::after {
  content: "";
  position: absolute;
  top: 0.22rem;
  bottom: 0.22rem;
  z-index: 1;
  width: 1px;
  pointer-events: none;
  background: rgba(216, 208, 167, 0.2);
}

.net-io-scope::before {
  left: 50%;
}

.net-io-scope::after {
  left: 75%;
  opacity: 0.58;
}

.net-io-scope svg {
  position: absolute;
  inset: 0.18rem 0.22rem;
  z-index: 2;
  width: calc(100% - 0.44rem);
  height: calc(100% - 0.36rem);
  overflow: visible;
}

.net-io-midline {
  fill: none;
  stroke: rgba(216, 208, 167, 0.16);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.net-io-trace {
  fill: none;
  stroke-linecap: square;
  stroke-linejoin: round;
  stroke-width: 1.15;
  vector-effect: non-scaling-stroke;
  transition: d 180ms linear;
}

.net-io-trace--in {
  stroke: rgba(255, 242, 187, 0.72);
}

.net-io-trace--out {
  stroke: rgba(216, 208, 167, 0.46);
  stroke-dasharray: 2 2;
}

.net-io-head {
  opacity: 0.9;
  transition:
    cx 180ms linear,
    cy 180ms linear;
}

.net-io-head--in {
  fill: rgba(255, 242, 187, 0.9);
}

.net-io-head--out {
  fill: rgba(216, 208, 167, 0.62);
}

.net-io-readouts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.1rem;
}

.bottom-hud .net-io-readouts .hud-value {
  margin: 0;
  font-size: 0.88rem;
  line-height: 1;
  white-space: nowrap;
}

.bottom-hud .net-io-readout span {
  font-size: inherit;
  line-height: inherit;
}

.bottom-hud .net-io-rate {
  display: inline-grid;
  grid-template-columns: var(--net-io-rate-value-width, auto) auto;
  align-items: baseline;
  column-gap: 0.12em;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.bottom-hud .net-io-rate > span {
  padding-left: 0;
  margin-left: 0;
  font-size: inherit;
  line-height: inherit;
}

.bottom-hud .net-io-rate-value {
  display: inline-block;
  width: var(--net-io-rate-value-width, auto);
  text-align: left;
}

.bottom-hud .net-io-rate-slot-measure {
  position: absolute;
  left: -9999px;
  width: auto;
  pointer-events: none;
  visibility: hidden;
  white-space: nowrap;
}

.sector-scan {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 0.22rem;
  width: 100%;
  padding: 0;
  margin: 0;
}

.sector-scan-grid {
  position: relative;
  display: flex;
  align-items: flex-end;
  gap: 1px;
  height: 1.7rem;
  padding: 0;
  margin: 0;
  overflow: hidden;
  background:
    linear-gradient(180deg, rgba(216, 208, 167, 0.05), rgba(216, 208, 167, 0.02) 50%, rgba(216, 208, 167, 0.06)),
    repeating-linear-gradient(0deg, rgba(216, 208, 167, 0.07) 0 1px, transparent 1px 6px),
    repeating-linear-gradient(90deg, rgba(216, 208, 167, 0.06) 0 1px, transparent 1px 14px),
    rgba(4, 7, 6, 0.22);
  border-top: 1px solid rgba(216, 208, 167, 0.14);
  border-bottom: 1px solid rgba(216, 208, 167, 0.18);
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

.sector-scan-grid::after {
  content: "";
  position: absolute;
  z-index: 2;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(4, 7, 6, 0.32) 0%,
    rgba(4, 7, 6, 0) 22%,
    rgba(4, 7, 6, 0) 78%,
    rgba(4, 7, 6, 0.38) 100%);
}

.sector-cell {
  position: relative;
  z-index: 1;
  display: block;
  flex: 1 1 0;
  min-width: 2px;
  height: var(--sector-cell-height, 0.5rem);
  background: linear-gradient(180deg, rgba(255, 242, 187, 0.85) 0%, rgba(255, 242, 187, 0.55) 45%, rgba(216, 208, 167, 0.18) 100%);
  box-shadow: 0 0 0.18rem rgba(255, 242, 187, 0.18);
  animation: sector-cell-pulse 2.4s ease-in-out infinite;
  animation-delay: var(--sector-cell-delay, 0ms);
  transition:
    height 520ms cubic-bezier(0.22, 0.68, 0.34, 1),
    opacity 520ms ease,
    box-shadow 520ms ease;
}

.sector-cell.is-spike {
  height: var(--sector-cell-spike, 1.4rem);
  animation: none;
  opacity: 1;
  box-shadow:
    0 0 0.32rem rgba(255, 242, 187, 0.5),
    0 0 0.7rem rgba(255, 242, 187, 0.18);
  transition:
    height 140ms cubic-bezier(0.18, 0.92, 0.32, 1.08),
    opacity 140ms ease,
    box-shadow 140ms ease;
}

.sector-scan-beam {
  position: absolute;
  z-index: 3;
  top: 0;
  bottom: 0;
  left: 0;
  width: 36%;
  pointer-events: none;
  background:
    linear-gradient(90deg,
      rgba(255, 242, 187, 0) 0%,
      rgba(255, 242, 187, 0.02) 45%,
      rgba(255, 242, 187, 0.1) 75%,
      rgba(255, 246, 200, 0.34) 90%,
      rgba(255, 252, 220, 0.82) 97%,
      rgba(255, 252, 220, 0.96) 100%);
  transform: translate3d(-100%, 0, 0);
  animation: sector-beam-sweep 5.2s linear infinite;
  will-change: transform, opacity;
}

.sector-scan-beam::after {
  content: "";
  position: absolute;
  top: -2px;
  bottom: -2px;
  right: 0;
  width: 1px;
  background: rgba(255, 252, 220, 0.95);
  box-shadow:
    0 0 0.32rem rgba(255, 252, 220, 0.7),
    0 0 0.7rem rgba(255, 242, 187, 0.32);
}

.sector-scan-readout {
  display: flex;
  align-items: baseline;
  max-width: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
  white-space: nowrap;
  font-size: 0.96rem;
  line-height: 1;
}

.sector-scan-code {
  display: inline-block;
  flex: 0 0 var(--sector-code-width, 5.2ch);
  width: var(--sector-code-width, 5.2ch);
  padding-right: 0.04rem;
  transition: color 180ms ease, text-shadow 180ms ease;
}

.sector-scan-code.is-pulse {
  color: rgba(255, 252, 220, 0.96);
  text-shadow: 0 0 0.36rem rgba(255, 242, 187, 0.45);
  transition: none;
}

.sector-scan-status {
  white-space: pre;
}

@keyframes sector-beam-sweep {
  0% {
    transform: translate3d(-100%, 0, 0);
    opacity: 0;
  }

  6% {
    opacity: 1;
  }

  78% {
    transform: translate3d(277.78%, 0, 0);
    opacity: 1;
  }

  82% {
    transform: translate3d(277.78%, 0, 0);
    opacity: 0;
  }

  100% {
    transform: translate3d(277.78%, 0, 0);
    opacity: 0;
  }
}

@keyframes sector-cell-pulse {
  0%,
  100% {
    opacity: 0.5;
  }

  50% {
    opacity: 0.78;
  }
}

.bottom-hud {
  position: absolute;
  right: calc(var(--screen-frame-gap) * 2);
  bottom: var(--screen-frame-gap);
  left: calc(var(--screen-frame-gap) * 2);
  display: grid;
  grid-template-columns: 1.1fr 1.7fr 1.2fr 1.7fr 1.2fr 2fr 0.8fr 0.8fr;
  gap: 0;
  min-height: 4.5rem;
  padding: 0.6rem 0;
  color: rgba(216, 208, 167, 0.56);
  background: transparent;
  border-top: 0;
  isolation: isolate;
}

.bottom-hud::before {
  background:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.03) 0 1px, transparent 1px 5px),
    rgba(4, 7, 6, 0.28);
  border-top: 1px solid rgba(216, 208, 167, 0.16);
}

.bottom-hud > div {
  position: relative;
  display: grid;
  align-content: start;
  gap: 0.24rem;
  padding: 0 1rem;
  border-left: 0;
}

.bottom-hud > div::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 0;
  border-left: 1px solid rgba(216, 208, 167, 0.12);
  -webkit-mask-image: var(--surface-wear-mask);
  mask-image: var(--surface-wear-mask);
  -webkit-mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  mask-position: var(--surface-wear-x, 0px) var(--surface-wear-y, 0px);
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: var(--surface-wear-size);
  mask-size: var(--surface-wear-size);
}

.bottom-hud > div:first-child::before {
  display: none;
}

.bottom-hud span {
  font-size: 0.94rem;
}

.bottom-hud .hud-value {
  color: rgba(232, 225, 185, 0.68);
  font-size: 1.08rem;
}

@media (max-width: 1050px) {
  .brand-hud {
    gap: 2.4rem;
    left: calc(var(--screen-frame-gap) * 2);
  }

  .brand-lockup h1 {
    font-size: 4.74rem;
  }

  .project-rig {
    left: 13vw;
    width: var(--project-rig-width, clamp(250px, 36vw, 390px));
  }

  .project-cartridge-rack {
    left: clamp(10px, 2.2vw, 36px);
    height: clamp(560px, 108vh, 1200px);
  }

  .project-label {
    left: 13vw;
  }

  .blog-rig {
    right: 10vw;
    width: var(--blog-rig-width, clamp(245px, 31vw, 350px));
  }

  .blog-frame-portal {
    right: 10vw;
    width: var(--blog-frame-open-width, var(--blog-frame-home-width, var(--blog-rig-width, clamp(245px, 31vw, 350px))));
  }

  .blog-label {
    width: 14.2rem;
  }

  .hud-stack,
  .session-hud {
    opacity: 0.45;
  }

  .bottom-hud {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (max-width: 760px) {
  body {
    overflow: hidden;
  }

  .scene::after {
    transition-duration: 480ms;
  }

  .brand-hud {
    top: calc(var(--screen-frame-gap) * 2);
    left: calc(var(--screen-frame-gap) * 2);
    gap: 1rem;
  }

  .system-readout,
  .session-hud,
  .hud-stack,
  .bottom-hud {
    display: none;
  }

  .brand-lockup h1 {
    font-size: 3.42rem;
  }

  .brand-lockup p {
    max-width: 17rem;
    font-size: 1.18rem;
  }

  .project-rig {
    top: 27vh;
    left: 4vw;
    width: var(--project-rig-width, 54vw);
    min-width: 210px;
    /* In mobile mode the rig participates in the projects-open zoom-in via
       --project-rig-transform (JS-computed dx/dy/scale), composed with a pan
       offset for the two-page slider. Keep a transition on the base rule so
       close also animates back to the rest pose. */
    transform: none;
    transition: transform 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  }

  /* Desktop lower panel never appears on mobile; the mobile variant takes
     over and uses a different frame image + button layout. */
  .project-lower-panel {
    display: none;
  }

  /* Shared layout primitives — the rack width formula is referenced by
     both the rack itself and the BACK TO SCREEN offset, and the height is
     used to compute the bottom-anchored top. Setting them on .scene lets
     siblings inherit them. */
  .scene {
    --project-mb-rack-width: min(55vw, calc(110vh * 439 / 1766));
    --project-mb-rack-height: calc(var(--project-mb-rack-width) * 1766 / 439);
  }

  /* The cartridge rack only exists on the mobile "cartridge" page, which the
     user reaches via swipe or by tapping SELECT CARTRIDGE. Hidden on the
     home view and snap-removed once is-projects-closing clears. */
  .project-cartridge-rack {
    display: none;
    /* Always overflow the viewport bottom by 30px so the bottom cap of the
       tower webp lands past the holographic frame — sustaining the lie
       that the cartridge track continues to a mechanism off-screen.
       Anchoring strategy:
        - If the natural "bottom-anchored top" sits below 1.5vh (i.e. the
          rack is short relative to the viewport), use the bottom-anchored
          value so the top of the rack lowers into the viewport.
        - Otherwise (the rack is already taller than the viewport), clamp
          top to 1.5vh and let the bottom overflow further — the top cap
          stays visible at the top of the page. The max() picks whichever
          gives the bottom-overflow guarantee without raising the rack. */
    left: 5vw;
    top: max(1.5vh, calc(100vh + 30px - var(--project-mb-rack-height)));
    width: var(--project-mb-rack-width);
    height: auto;
    /* Override the desktop rises-from-below pose: mobile rests off-LEFT so
       the close transition slides off the cartridge page horizontally
       rather than diagonally. */
    transform: translate3d(-100vw, 0, 0);
  }

  /* ------- Open state ------- */
  /* The rig zooms into the upper portion of the viewport (JS-computed open
     box) and stays panned by --project-mb-pan-x. Pan composes with the
     rig-transform var so a single transition keeps both axes in sync. */
  .scene.is-projects-open .project-rig {
    transform: translate3d(var(--project-mb-pan-x, 0px), 0, 0)
      var(--project-rig-transform, none);
  }

  /* Bob keeps the rig hovering on the home page; pause it once the rig has
     a fixed open pose so the screen doesn't visibly drift while the user is
     trying to read the lower panel. */
  .scene.is-projects-open .project-bob {
    animation-play-state: paused;
  }

  /* Mobile plane: match the rig's 480ms transform transition so the
     screen's positional zoom (rig translate+scale) and the perspective
     un-tilt (plane rotateZ/X/Y) reach the open pose ON THE SAME FRAME.
     With the desktop base of 680ms, the rig finished its position at
     480ms while the plane kept rotating for another 200ms — reading as
     "screen moves into place, then tilts" instead of "camera dollies in
     while screen stays still" (the intended illusion). The shadow's
     opacity fade also needs to land at the same 480ms beat so the
     lighting reads as one motion. */
  .project-plane {
    transition: transform 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  }
  .project-plane::after {
    transition: opacity 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  }

  /* Tilt off — the user is looking at the screen straight-on now, not at the
     resting hologram. Same flattened pose used by the desktop open state. */
  .scene.is-projects-open .project-plane {
    transform: perspective(900px) rotateZ(0deg) rotateX(0deg) rotateY(0deg);
  }

  /* Mobile lower panel: visible during the staged-open and closing
     transitions; tucked entirely off-display otherwise. The staging
     class (added briefly by JS before is-projects-open) flips display
     to block so the panel commits a real paint at the drop-start pose
     BEFORE the open class lands — without that prior paint, the browser
     treats the open class as the first style for the element and skips
     the transition entirely (display: none → block disables
     transitions). */
  .scene.is-projects-staging .project-lower-panel-mb,
  .scene.is-projects-open .project-lower-panel-mb,
  .scene.is-projects-closing .project-lower-panel-mb {
    display: block;
  }

  /* ------- Staged open · step 1: the panel waits off-stage ------- */
  /* The open is two steps, like desktop: step 1 the rig travels into its
     open position (its own 480ms transform transition), THEN step 2 the
     panel emerges. While the rig travels, the panel holds at this
     drop-start pose — parked at its open X but lifted by
     --panel-mb-drop-dy so its pre-shrunk body sits fully behind the
     open-position monitor, and flat (face-on, matching the un-tilted
     open monitor it hides behind). opacity: 0 keeps it from flashing at
     the open coords before the monitor has travelled in to occlude it;
     the staged transition snaps it opaque exactly as the drop begins,
     while it is still tucked behind the settled monitor. transition:
     none so entering this pose out of display: none is instant. */
  .scene.is-projects-staging .project-lower-panel-mb {
    opacity: 0;
    translate: var(--project-mb-pan-x, 0px) calc(-1 * var(--panel-mb-drop-dy, 0px));
    scale: var(--panel-mb-drop-scale, 0.7);
    transform: perspective(900px) rotateZ(0deg) rotateX(0deg) rotateY(0deg);
    transition: none;
  }

  /* Open pose: face-on, full scale, at the panel's inline open coords.
     This doubles as the STEADY post-open state — a horizontal swipe
     re-uses this rule's transition for its release snap, so it stays a
     plain no-delay transition. The staged open MOTION is layered on top
     by .is-projects-mb-opening below; this rule only owns the open pose
     + the swipe-snap timing. */
  .scene.is-projects-open .project-lower-panel-mb {
    pointer-events: auto;
    opacity: 1;
    translate: var(--project-mb-pan-x, 0px) 0;
    scale: 1;
    transform: perspective(900px) rotateZ(0deg) rotateX(0deg) rotateY(0deg);
    transition:
      translate 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8),
      scale 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8),
      transform 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8),
      opacity 0s linear;
  }

  /* ------- Staged open · step 2: drop, then scale ------- */
  /* is-projects-mb-opening rides alongside is-projects-open for the
     duration of the open animation only (JS drops it once settled). It
     overrides the transition so step 2 plays as two back-to-back beats —
     the mobile panel is tall, so a single straight slide down at full
     scale would tower over the monitor:
       2a DROP  (translate, 480→780ms) — the panel slides straight down
                 out from behind the monitor's bottom edge, held the
                 whole way at the small --panel-mb-drop-scale.
       2b SCALE (scale, 780→1080ms) — anchored at its top-center
                 (transform-origin 50% 0%) the panel grows from
                 drop-scale to 1, reading as it advancing toward the
                 camera.
     opacity snaps in at 480ms so the panel appears already tucked behind
     the by-then-settled monitor, exactly as the drop starts. Same
     specificity as the rule above, so source order (this rule later)
     wins for `transition` while both classes are present. */
  .scene.is-projects-mb-opening .project-lower-panel-mb {
    transition:
      opacity 0s linear 480ms,
      translate 300ms cubic-bezier(0.33, 0.2, 0.67, 0.8) 480ms,
      scale 300ms cubic-bezier(0.33, 0.2, 0.67, 0.8) 780ms;
  }

  .project-lower-panel-mb .project-panel-stats {
    grid-template-columns: 1fr;
    gap: 0.2rem;
    padding-right: 0.12rem;
  }

  .project-lower-panel-mb .project-panel-stat-row {
    grid-template-columns: minmax(0, 5.8rem) minmax(0, 1fr);
    gap: 0.42rem;
    white-space: normal;
    overflow: visible;
  }

  .project-lower-panel-mb .project-panel-stat-label,
  .project-lower-panel-mb .project-panel-stat-value {
    min-width: 0;
    line-height: 1.05;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    overflow-wrap: anywhere;
  }

  /* Close — one motion (matches desktop): translate / scale / transform
     fall back to the base style (= home pose, tucked into the home rig's
     screen) and interpolate together over 480ms. Opacity snaps to 0 at
     480ms so the panel reads as continuously visible through the motion
     and cleanly hidden once it's tucked behind the home rig. */
  .scene.is-projects-closing .project-lower-panel-mb {
    opacity: 0;
    transition:
      translate 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8),
      scale 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8),
      transform 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8),
      opacity 0s linear 480ms;
  }

  /* Cartridge rack and back-to-screen sit one viewport-width to the left of
     the screen page. They become visible when --project-mb-pan-x advances
     toward +100vw (cartridge page). */
  .scene.is-projects-open .project-cartridge-rack,
  .scene.is-projects-closing .project-cartridge-rack {
    display: block;
  }

  .scene.is-projects-open .project-cartridge-rack {
    pointer-events: auto;
    touch-action: none;
    /* Top-anchored — no Y centering. Pan composes with the resting -100vw
       offset to slide the rack in from the left. */
    transform: translate3d(calc(var(--project-mb-pan-x, 0px) - 100vw), 0, 0);
    transition: transform 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
    transition-delay: 0ms;
  }

  /* BACK TO SCREEN — positioned just past the rack's right edge on the
     cartridge page. Left offset mirrors the rack's width formula above so
     the button always lands flush with whichever bound is winning. Font
     size and padding scale down at narrow viewports so the label fits in
     the remaining horizontal space. */
  .project-back-to-screen {
    left: calc(5vw + var(--project-mb-rack-width) + 5vw);
    top: 50%;
    transform: translate3d(-100vw, -50%, 0);
    font-size: clamp(0.74rem, 3.1vw, 1.04rem);
    padding: clamp(0.46rem, 1.8vw, 0.74rem) clamp(0.58rem, 2.2vw, 1.05rem);
    gap: clamp(0.36rem, 1.3vw, 0.62rem);
  }

  .scene.is-projects-open .project-back-to-screen,
  .scene.is-projects-closing .project-back-to-screen {
    display: flex;
  }

  .scene.is-projects-open .project-back-to-screen {
    pointer-events: auto;
    /* Compose pan with -50% Y so the button stays vertically centered
       through any pan position. */
    transform: translate3d(calc(var(--project-mb-pan-x, 0px) - 100vw), -50%, 0);
  }

  /* During an active swipe, kill transitions so the elements track the
     finger 1:1 without easing in toward each step's --project-mb-pan-x
     update. The release path re-enables transitions for the snap. */
  .scene.is-projects-mb-dragging .project-rig,
  .scene.is-projects-mb-dragging .project-lower-panel-mb,
  .scene.is-projects-mb-dragging .project-cartridge-rack,
  .scene.is-projects-mb-dragging .project-back-to-screen {
    transition: none;
  }

  .project-cartridge-rack.is-cartridge-dragging .project-cartridge-track {
    transition: none;
  }

  /* The desktop rule slides the blog rig 50vw to the right when projects
     opens — enough to clear the holographic frame on wide viewports, not
     enough on narrow ones (a min-width:230px rig at right:-4vw still pokes
     into the visible area at 320–480px viewports). Push it a full
     viewport-width on mobile so it's flush with the off-screen state of
     the rest of the home content. */
  .scene.is-projects-open .blog-rig,
  .scene.is-projects-open .blog-frame-portal {
    transform: translate3d(100vw, 0, 0);
  }

  .scene.is-projects-closing .label-card.project-label,
  .scene.is-projects-closing .label-card.blog-label,
  .scene.is-blog-closing .label-card.project-label,
  .scene.is-blog-closing .label-card.blog-label {
    transition:
      left 220ms ease,
      top 220ms ease,
      transform 220ms cubic-bezier(0.18, 0.82, 0.24, 1) 260ms,
      opacity 100ms linear 260ms;
  }

  .project-label {
    top: 49vh;
    left: 6vw;
    width: 11.4rem;
  }

  .blog-rig {
    right: -4vw;
    bottom: 10vh;
    width: var(--blog-rig-width, 52vw);
    min-width: 230px;
  }

  .blog-frame-portal {
    right: -4vw;
    bottom: 10vh;
    width: var(--blog-frame-open-width, var(--blog-frame-home-width, var(--blog-rig-width, 52vw)));
    min-width: 230px;
  }

  .blog-rig {
    transition: transform 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  }

  .blog-frame-portal {
    transition: transform 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  }

  .scene.is-blog-open .blog-rig-swing,
  .scene.is-blog-closing .blog-rig-swing,
  .scene.is-blog-open .blog-frame-swing,
  .scene.is-blog-closing .blog-frame-swing {
    transition: transform 480ms cubic-bezier(0.33, 0.2, 0.67, 0.8);
  }

  .scene.is-blog-reader-visible .blog-panel--bottom-main {
    background: transparent;
  }

  .scene.is-blog-reader-visible .blog-panel--bottom-main .blog-panel-content {
    visibility: hidden;
  }

  .blog-reader-overlay {
    box-shadow:
      inset 0 0 0 1px rgba(216, 208, 167, 0.16),
      inset 0 0 28px rgba(0, 0, 0, 0.7),
      0 0 14px rgba(127, 188, 195, 0.08);
  }

  .blog-reader-overlay::after {
    opacity: 0.34;
  }

  .blog-reader--mobile-text,
  .blog-reader--mobile-controls {
    width: 100%;
    height: 100%;
    min-height: 0;
  }

  .blog-reader--mobile-text {
    display: block;
  }

  .blog-reader--mobile-text .blog-reader-article {
    height: 100%;
    overflow: hidden;
  }

  .blog-reader--mobile-text .blog-reader-copy {
    height: 100%;
    overflow-y: auto;
    padding: 0.54rem 0.58rem 0.66rem;
  }

  .blog-reader--mobile-text .blog-reader-date {
    margin-bottom: 0.2rem;
    font-size: 0.85rem;
  }

  .blog-reader--mobile-text .blog-reader-title {
    margin-bottom: 0.34rem;
    font-size: 1.35rem;
    line-height: 0.96;
  }

  .blog-reader--mobile-text .blog-reader-copy p {
    margin-bottom: 0.46rem;
    font-size: 0.95rem;
    line-height: 1.12;
  }

  .blog-reader--mobile-text .blog-reader-project-links {
    gap: 0.28rem;
    margin-top: 0.72rem;
    padding-top: 0.48rem;
  }

  .blog-reader--mobile-text .blog-reader-project-links-label {
    font-size: 0.86rem;
  }

  .blog-reader--mobile-text .blog-reader-project-link {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.16rem;
    padding: 0.34rem 0.42rem;
  }

  .blog-reader--mobile-text .blog-reader-project-link-title,
  .blog-reader--mobile-text .blog-reader-project-link-meta {
    white-space: normal;
    overflow-wrap: anywhere;
  }

  .blog-reader--mobile-controls {
    grid-template-columns: minmax(6.6rem, 34%) minmax(0, 1fr);
  }

  .blog-reader--mobile-controls .blog-reader-list {
    min-height: 0;
  }

  .blog-reader--mobile-controls .blog-reader-posts {
    padding: 0;
  }

  .blog-reader--mobile-controls .blog-reader-post {
    gap: 0.1rem;
    padding: 0.3rem 0.34rem;
    overflow: visible;
  }

  .blog-reader--mobile-controls .blog-reader-post-date {
    font-size: 0.69rem;
  }

  .blog-reader--mobile-controls .blog-reader-post-title {
    font-size: 0.85rem;
    line-height: 1.05;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    overflow-wrap: anywhere;
  }

  .blog-reader--mobile-controls .blog-reader-home {
    padding: 0.42rem 0.34rem;
    font-size: 0.78rem;
    letter-spacing: 0.04em;
  }

  .blog-reader--mobile-controls .blog-reader-media {
    grid-template-rows: minmax(0, 1fr) 2.45rem;
    gap: 0.28rem;
    height: 100%;
    min-height: 0;
    padding: 0.34rem;
    border-bottom: 0;
  }

  .blog-reader--mobile-controls .blog-reader-thumb {
    flex-basis: 3.7rem;
  }

  .blog-reader--mobile-controls .blog-reader-empty {
    min-height: 0;
    font-size: 0.85rem;
  }

  .blog-reader-overlay--bottom .blog-lightbox {
    place-items: stretch;
  }

  .blog-reader-overlay--bottom .blog-lightbox img {
    width: 100%;
    height: 100%;
    max-height: none;
    padding: 0.42rem 0.54rem 0;
    object-fit: contain;
  }

  .blog-reader-overlay--bottom .blog-lightbox-footer {
    width: 100%;
    padding: 0.42rem 0.6rem 0.54rem;
  }

  .blog-reader-overlay--bottom .blog-lightbox-back {
    font-size: 0.95rem;
  }

  .blog-label {
    top: 58vh;
    left: auto;
    right: 1rem;
    width: 13rem;
  }

  .label-card {
    min-height: 4.4rem;
    padding: 0.82rem 0.9rem;
  }

  .label-card .label-title {
    font-size: 1.34rem;
  }

  .label-card span {
    font-size: 1.06rem;
  }
}

/* Paint-cost hints — purely performance, no visual effect. */
.hud-panel,
.bottom-hud > div,
.power-draw,
.memory-map,
.memory-bank-grid,
.memory-bank-track,
.data-stream-bus,
.data-stream-cell,
.link-carrier,
.blog-reader-overlay,
.core-temp,
.core-temp-diode,
.core-temp-node,
.cpu-load-scope,
.net-io-scope,
.sector-scan-grid {
  contain: layout style paint;
}

.core-temp-diode,
.memory-map,
.memory-bank-grid,
.data-stream-bus,
.cpu-load-scope,
.net-io-scope {
  transform: translateZ(0);
}
