/* ─── Fonts ──────────────────────────────────────────────────────── */
@import url('https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400;0,500;1,400;1,500&display=swap');

@font-face { font-family:'NHaasGrotesk'; src:url('fonts/NHaasGroteskTXPro-75Bd.ttf') format('truetype'); font-weight:700; font-display:swap; }
@font-face { font-family:'ABCConnectMono'; src:url('fonts/ABCConnectMono-Phillips.otf') format('opentype'); font-display:swap; }
@font-face { font-family:'UntitledSans'; src:url('fonts/UntitledSans2-Regular.otf') format('opentype'); font-display:swap; }
@font-face { font-family:'ABCConnectNailItalic'; src:url('fonts/ABCConnect-NailItalic.otf') format('opentype'); font-style:italic; font-display:swap; }

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

html, body {
  width:100%; height:100vh;
  overflow:hidden;
  background:#141414;
  /* Grayscale smoothing so EB Garamond renders at the same light weight
     as in Figma — without this, Chrome/macOS subpixel rendering makes the
     serif text read noticeably thicker than the design. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* ═══ LAYOUT — machine+CP column fixed-centered ══════════════════
   Machine is always the same pixel size, centered horizontally.
   The bio and footer are fixed to viewport edges.
═══════════════════════════════════════════════════════════════════ */
.machine-cp-col {
  position: fixed;
  left: 50%;
  top: 127px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  z-index: 15;   /* above proj-carousel(5) and proj-lock(6) so Panel-2 nav stays on top */
  /* Reserve layout space above fixed control panel */
  padding-bottom: 198px;
  transition: transform 0.95s cubic-bezier(0.4, 0, 0.15, 1);
}

/* ─── Bio text — fixed top-left ──────────────────────────────── */
.bio-text {
  position: fixed;
  top: 22px;
  left: 24px;
  z-index: 40;
  font-family: 'EB Garamond', 'Georgia', serif;
  font-weight: 400;
  font-size: 18px;
  line-height: 1.15;
  letter-spacing: -0.2px;
  color: #7f7f7f;
  text-align: left;
  pointer-events: none;
  opacity: 0;
  transform: translateY(-30px);
  transition: opacity 0.7s ease,
              transform 0.85s cubic-bezier(0.22, 1, 0.36, 1);
}
.bio-text.visible {
  opacity: 1;
  transform: translateY(0);
}
.bio-name {
  color: #f7f7f7;
  font-weight: 400;
}

/* © line — top-right — Figma 100:1370 */
.copyright-line {
  position: fixed;
  top: 14px;
  right: clamp(14px, 3.5vw, 24px);
  z-index: 40;
  max-width: min(304px, 42vw);
  font-family: 'EB Garamond', 'Georgia', serif;
  font-weight: 400;
  font-size: 18px;
  line-height: 1.15;
  letter-spacing: -0.2px;
  color: #a2a2a2;
  text-align: right;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.65s ease 4.85s,
              transform 0.85s cubic-bezier(0.22, 1, 0.36, 1) 4.85s;
  transform: translateY(-14px);
}
.copyright-line.visible {
  opacity: 1;
  transform: translateY(0);
}

/* ═══ MACHINE WRAP ══════════════════════════════════════════════ */
.machine-wrap {
  position: relative;
  width: 361.379px;
  height: 518.064px;
  flex-shrink: 0;
}

/* ═══ MACHINE COVER — frost glass over machine (loading state) ═══
   Figma shell 332.932 × 547.908 + TOP cap room 22.21px tall. */
.machine-cover {
  position: absolute;
  left: calc((361.379px - 332.932px) / 2);
  top: -22.21px;
  width: 332.932px;
  height: 570.118px;
  z-index: 30;
  pointer-events: none;
  opacity: 1;
  transform: translateY(0);
  transition: transform 2.6s cubic-bezier(0.6, 0.04, 0.4, 1);
}
.machine-cover.hidden {
  transform: translateY(-200%);
}

.cover-top-glass {
  position: absolute;
  left: 1.2px; top: 0;
  width: 330.68px; height: 25.87px;
  clip-path: polygon(6.62% 10.26%, 94.27% 10.93%, 98.92% 90.91%, 1.08% 90.91%);
  -webkit-clip-path: polygon(6.62% 10.26%, 94.27% 10.93%, 98.92% 90.91%, 1.08% 90.91%);
  background: rgba(108,108,108,0.18);
  backdrop-filter: blur(10px) saturate(1.05);
  -webkit-backdrop-filter: blur(10px) saturate(1.05);
  pointer-events: none;
  z-index: 4;
}
.cover-top {
  position: absolute;
  left: 1.2px; top: 0;
  width: 330.68px; height: 25.87px;
  display: block;
  pointer-events: none;
  z-index: 5;
}
.cover-shell {
  position: absolute;
  left: 0; top: 22.21px;
  width: 332.932px; height: 547.908px;
  border-radius: 7.114px;
  background: rgba(108,108,108,0.2);
  backdrop-filter: blur(14px) saturate(1.05);
  -webkit-backdrop-filter: blur(14px) saturate(1.05);
  z-index: 1;
}
.cover-stroke {
  position: absolute;
  left: 7.79px; top: 22.21px;
  width: 320.94px; height: 543.97px;
  display: block;
  pointer-events: none;
  z-index: 2;
}
.cover-inset {
  position: absolute;
  left: 20.63px; top: calc(22.21px + 20.02px);
  width: 292.064px; height: 509.656px;
  border-radius: 5.174px;
  background: rgba(0,0,0,0.2);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  pointer-events: none;
  z-index: 2;
}
.cover-circle {
  position: absolute;
  left: calc(50% - 96.461px - 0.59px);
  top: calc(22.21px + 187.84px);
  width: 192.922px; height: 193.153px;
  border-radius: 50%;
  background: rgba(0,0,0,0.28);
  opacity: 0.6;
  filter: blur(1.5px);
  pointer-events: none;
  z-index: 3;
}
.cover-brand-wrap {
  position: absolute;
  left: calc(259.99px - 38.065px);
  top: calc(22.21px + 128.46px);
  width: 76.13px; height: 55.289px;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 4;
}
.cover-brand {
  font-family: 'ABCConnectNailItalic', serif;
  font-style: italic;
  font-weight: 400;
  font-size: 17.837px;
  color: #626262;
  line-height: 0.81;
  letter-spacing: -0.1984px;
  text-align: center;
  display: block;
  transform: rotate(-8.93deg);
  user-select: none;
}

/* ─── Machine TOP cap ─────────────────────────────────────────── */
.machine-top {
  position: absolute;
  left: 38.46px;
  top: -20.17px;
  width: 280.68px;
  height: 21.17px;
  display: block;
  pointer-events: none;
  z-index: 1;
}

/* ─── Panel 1 ─────────────────────────────────────────────────── */
/* Figma 123:2194 — radial-gradient FILL + 1px radial-gradient STROKE
   at 20% opacity (the missing radial highlight on the metal frame).
   Both painted inside panel1-frame.svg so they scale together. No CSS
   border — the gradient stroke lives inside the SVG. */
.panel1-frame {
  position: absolute;
  left: 37.5px; top: 0;
  width: 281.642px; height: 373.18px;
  background: url('assets/panel1-frame.svg') no-repeat center center / 100% 100%;
}

/* ─── Panel 2 ─────────────────────────────────────────────────── */
/* Figma 123:2298 — opaque dark linear-gradient fill + same radial-gradient
   stroke as Panel 1 at 20% opacity. Bundled into panel2-frame.svg. */
.panel2-frame {
  position: absolute;
  left: 37.5px; top: 372.55px;
  width: 281.642px; height: 137.893px;
  background: url('assets/panel2-frame.svg') no-repeat center center / 100% 100%;
}

/* ─── Face shading + top panel ───────────────────────────────── */
.face-shading {
  position: absolute;
  left: 65.24px; top: 32.95px;
  width: 226.157px; height: 305.918px;
  border-radius: 8px;
  overflow: hidden;
  background: url('assets/shading-panel.svg') no-repeat center / 100% 100%;
  pointer-events: none;
  z-index: 1;
}
.face-panel {
  position: absolute;
  left: 71.24px; top: 37.28px;
  width: 215.377px; height: 295.722px;
  border-radius: 4px;
  overflow: hidden;
  background: url('assets/top-panel.svg') no-repeat center / 100% 100%;
  pointer-events: none;
  z-index: 2;
}

/* ═══ CLAW MACHINE SCREEN — overflow:hidden clips claw to frame ═ */
.machine-screen {
  position: absolute;
  left: 72.93px; top: 39.14px;
  width: 212px; height: 292px;
  border-radius: 3px;
  overflow: hidden;
  isolation: isolate;
}

.screen-bg-light {
  position: absolute; inset: 0; border-radius: inherit;
  background:
    radial-gradient(ellipse 80% 50% at 50% 0%,
      rgba(226,226,226,0.6) 0%,
      rgba(164,164,164,0.3) 50%,
      rgba(102,102,102,0)   100%),
    linear-gradient(90deg, rgb(240,240,240) 0%, rgb(240,240,240) 100%);
}

.screen-bg-dark {
  position: absolute; inset: 0; border-radius: inherit;
  background:
    linear-gradient(270deg,
      rgba(24,24,24,0.5)  0%,
      rgba(11,11,11,0.5)  12.5%,
      rgba(5,5,5,0.5)     53.516%,
      rgba(8,8,8,0.5)     90.558%,
      rgba(30,30,30,0.5)  100%),
    radial-gradient(ellipse 80% 55% at 50% 0%,
      rgba(226,226,226,0.28) 0%,
      rgba(164,164,164,0.14) 50%,
      rgba(102,102,102,0)    100%),
    linear-gradient(180deg, rgb(81,81,81) 0%, rgb(0,0,0) 100%);
  box-shadow: inset 0px 0.876px 1.753px 0px rgba(0,0,0,0.25);
}

/* ═══ CLAW ═══════════════════════════════════════════════════════ */
.claw-rig {
  position: absolute;
  top: 0; left: 50%;
  transform: translateX(-50%);
  z-index: 3; pointer-events: none;
  transition: left .38s cubic-bezier(.4,0,.2,1);
}
.claw-rig.transitioning {
  transition: left .38s cubic-bezier(.4,0,.2,1), top .52s ease;
}
.claw-stack {
  position: relative;
  width: 212px;
  height: 292px;
  transition: filter .2s;
}
.claw-stack.gripping { filter: brightness(1.1); }

/* Single-image claw (Figma 132:2893). Image is 103×302 at natural scale.
   We render it at natural size, centered horizontally, positioned so the
   bottom of the fingers lands at y≈180 within the 292px screen and the
   cable extends above (clipped by .machine-screen overflow:hidden). */
.claw-full {
  position: absolute;
  left: 50%;
  top: -122px;
  width: 103px;
  height: 302px;
  transform: translateX(-50%);
  display: block;
  pointer-events: none;
  z-index: 1;
  -webkit-user-drag: none;
  user-select: none;
}

.claw-half {
  position: absolute;
  left: 0; top: 0;
  width: 212px; height: 292px;
  pointer-events: none;
  z-index: 2;
}
.clh img { display: block; object-fit: contain; }

/* ─── Left outer finger ─── */
.cl-fo-l {
  position: absolute;
  left: 67.20px; top: 95.91px;
  width: 26.494px; height: 28.375px;
  display: flex; align-items: center; justify-content: center;
}
.cl-fo-spin {
  width: 22.694px; height: 24.982px;
  transform-origin: center center; flex-shrink: 0;
}
.cl-fo-l .cl-fo-spin { transform: rotate(9.47deg); }
.cl-fo-spin img { width: 100%; height: 100%; object-fit: contain; }

/* ─── Left inner finger ─── */
.cl-fi-l {
  position: absolute;
  left: 58.07px; top: 112.10px;
  width: 30.662px; height: 53.961px;
  display: flex; align-items: center; justify-content: center;
}
.cl-fi-spin-l {
  width: 18.853px; height: 50.904px;
  transform: scaleY(-1) rotate(165.93deg);
  transform-origin: center center; flex-shrink: 0;
}
.cl-fi-frame { position: relative; width: 100%; height: 100%; overflow: hidden; }
.cl-fi-inset {
  position: absolute;
  top: 2.74%; right: 1.53%; bottom: 0.46%; left: 5.79%;
}
.cl-fi-inset img { width: 100%; height: 100%; object-fit: contain; }

/* ─── Left screws ─────────────────────────────────────────────────
   Each screw is a Figma "centering wrapper" (size = outer bounding box,
   flex-centers the rotated image inside) holding an image at the actual
   Figma image size. This keeps the rotation pivot on the wrapper centre
   exactly as Figma renders it. All values scaled from Figma 123:2219
   by 212 / 227.6 = 0.93146.
   ─────────────────────────────────────────────────────────────── */
.cl-fs-l-o {
  position: absolute; left: 69.78px; top: 118.41px;
  width: 3.860px; height: 3.860px;
  display: flex; align-items: center; justify-content: center;
  transform: rotate(14.93deg);
}
.cl-fs-l-i {
  position: absolute; left: 70.37px; top: 119.00px;
  width: 2.687px; height: 2.687px;
  display: flex; align-items: center; justify-content: center;
  transform: rotate(14.93deg);
}
.cl-ft-l-o {
  position: absolute; left: 85.52px; top: 105.23px;
  width: 4.003px; height: 4.003px;
  display: flex; align-items: center; justify-content: center;
  transform: rotate(18.82deg);
}
.cl-ft-l-i {
  position: absolute; left: 86.13px; top: 105.84px;
  width: 2.786px; height: 2.786px;
  display: flex; align-items: center; justify-content: center;
  transform: rotate(18.82deg);
}
.cl-fs-l-o img, .cl-fs-r-o img,
.cl-ft-l-o img, .cl-ft-r-o img {
  width: 3.154px; height: 3.154px; object-fit: contain; flex: none;
}
.cl-fs-l-i img, .cl-fs-r-i img,
.cl-ft-l-i img, .cl-ft-r-i img {
  width: 2.195px; height: 2.195px; object-fit: contain; flex: none;
}

/* ─── Right outer finger ─── */
.cl-fo-r {
  position: absolute;
  left: 118.49px; top: 95.91px;
  width: 26.494px; height: 28.375px;
  display: flex; align-items: center; justify-content: center;
}
.cl-fo-spin-r { transform: scaleY(-1) rotate(170.53deg); }

/* ─── Right inner finger ─── */
.cl-fi-r {
  position: absolute;
  left: 123.42px; top: 112.10px;
  width: 30.662px; height: 53.961px;
  display: flex; align-items: center; justify-content: center;
}
.cl-fi-spin-r {
  width: 18.853px; height: 50.904px;
  transform: rotate(14.07deg);
  transform-origin: center center; flex-shrink: 0;
}

/* ─── Right screws (mirrors of left via scaleY(-1)) ───────────── */
.cl-fs-r-o {
  position: absolute; left: 138.52px; top: 118.41px;
  width: 3.860px; height: 3.860px;
  display: flex; align-items: center; justify-content: center;
  transform: scaleY(-1) rotate(165.07deg);
}
.cl-fs-r-i {
  position: absolute; left: 139.11px; top: 119.00px;
  width: 2.687px; height: 2.687px;
  display: flex; align-items: center; justify-content: center;
  transform: scaleY(-1) rotate(165.07deg);
}
.cl-ft-r-o {
  position: absolute; left: 122.63px; top: 105.23px;
  width: 4.003px; height: 4.003px;
  display: flex; align-items: center; justify-content: center;
  transform: scaleY(-1) rotate(161.18deg);
}
.cl-ft-r-i {
  position: absolute; left: 123.24px; top: 105.84px;
  width: 2.786px; height: 2.786px;
  display: flex; align-items: center; justify-content: center;
  transform: scaleY(-1) rotate(161.18deg);
}
.cl-fs-r-o img, .cl-fs-r-i img,
.cl-ft-r-o img, .cl-ft-r-i img { width: 100%; height: 100%; object-fit: contain; }

/* ─── Project circles ─────────────────────────────────────────── */
.circles-bin { position:absolute; inset:0; z-index:1; pointer-events:none; overflow:hidden; }
.proj-circle {
  position: absolute; border-radius: 50%; overflow: hidden;
  transition: opacity 0.35s ease;
  will-change: left, top;
  /* circles-bin sets pointer-events:none; re-enable on each ball so the
     project can be selected by clicking it directly (not just via the
     joystick / claw). */
  pointer-events: auto;
  cursor: pointer;
}
.proj-circle img {
  width:100%; height:100%; object-fit:cover; border-radius:50%; pointer-events:none;
  /* Non-active balls defocus to a soft blur with a slight desaturation; the
     active ball stays sharp and vivid. Kept on the gentle side so balls
     remain legible behind the in-focus claw. */
  filter: blur(3.2px) brightness(0.78) saturate(0.85);
  transition: filter 0.32s ease;
}
.proj-circle.active-target img { filter: blur(0) brightness(1) saturate(1); }
.proj-circle.grabbed { z-index:4; }
.proj-circle.grabbed img { filter: blur(0) brightness(1) saturate(1); }
.proj-circle.hidden  { opacity:0 !important; pointer-events:none; }

/* ─── Screen glass reflections — Figma Landing 124:2360 ────────── */
/* Bottom band: soft white reflection at the chute. Figma specs the layer
   at opacity 0.32 but the same value reads ~2x stronger in a browser due
   to gamma/blend differences — dialed back so it stays subtle. */
.screen-glass-bottom {
  position: absolute;
  left: -7.50px; top: 248.00px;
  width: 220.39px; height: 55.81px;
  opacity: 0.15;
  background: #ffffff;
  filter: blur(3.85px);
  pointer-events: none; z-index: 2;
}
/* Top band: barely-there gradient (solid → transparent over the lower
   ~20%) for a top-of-glass shine. */
.screen-glass-top {
  position: absolute;
  left: -1.43px; top: 27.15px;
  width: 220.39px; height: 120.40px;
  opacity: 0.04;
  background: linear-gradient(180deg, #ffffff 0%, #ffffff 79.676%, rgba(255,255,255,0) 100%);
  filter: blur(2.37px);
  pointer-events: none; z-index: 2;
}

/* ─── Screws — Panel 1 ───────────────────────────────────────── */
.screw-wrap {
  position: absolute;
  width: 7.146px; height: 7.146px;
  pointer-events: none; z-index: 4;
}
.screw-outer { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.screw-inner {
  position: absolute;
  width: 4.973px; height: 4.973px;
  left: 1.087px; top: 1.087px;
  display: block;
}
.s-tl1 { left: 43.88px; top: 5.59px; }
.s-tr1 { left: 306.12px; top: 5.59px; }
.s-bl1 { left: 43.88px; top: 359.59px; }
.s-br1 { left: 306.12px; top: 359.59px; }
.s-tl2 { left: 43.88px; top: 380.60px; }
.s-tr2 { left: 306.12px; top: 380.60px; }
.s-bl2 { left: 43.88px; top: 498.64px; }
.s-br2 { left: 306.12px; top: 498.64px; }

/* ─── 808MISC brand text ──────────────────────────────────────── */
.brand-text {
  position: absolute;
  left: 50%; top: 386.26px;
  transform: translateX(-50%);
  font-family: 'ABCConnectMono','Andale Mono','Courier New',monospace;
  font-weight: 400;
  font-size: 36.647px;
  letter-spacing: -0.3865px;
  text-align: center;
  text-transform: uppercase;
  white-space: nowrap;
  user-select: none;
  width: 178.153px;
  line-height: 1.01;
  color: transparent;
  -webkit-text-stroke: 0.5px rgba(95,95,95,0.55);
}

/* ─── Drop slot ───────────────────────────────────────────────── */
.slot {
  position: absolute;
  left: 50%; top: 431.18px;
  transform: translateX(-50%);
  width: 98.684px; height: 68.76px;
  border: 0.5px solid #000;
  border-radius: 2.547px;
  overflow: hidden;
  z-index: 9;
}
.slot-outer-panel {
  position: absolute;
  left: -0.5px; top: -0.5px;
  width: 186.464px; height: 270.905px;
  border-radius: 3.896px;
  background:
    radial-gradient(ellipse 100% 80% at 50% -10%,
      rgba(226,226,226,0.6) 0%,
      rgba(164,164,164,0.3) 50%,
      rgba(102,102,102,0) 100%),
    linear-gradient(90deg, rgb(240,240,240) 0%, rgb(240,240,240) 100%);
  box-shadow: inset 0px 0.812px 1.625px 0px rgba(0,0,0,0.25);
  z-index: 1;
  pointer-events: none;
}
.slot-recess {
  position: absolute; inset: 0;
  border-radius: 2.547px;
  background: linear-gradient(227.56deg, rgb(10,10,10) 17.188%, rgb(16,16,16) 102.65%);
  box-shadow: inset 0px 0.812px 1.625px 0px rgba(0,0,0,0.25);
  z-index: 2;
  pointer-events: none;
}
.slot-ball-img {
  position: absolute;
  left: 50%; top: 0;
  transform: translate(-50%, -180%);
  width: 60px; height: 60px;
  border-radius: 50%; object-fit: cover;
  opacity: 0; z-index: 10;
}
.slot.slot-filled .slot-ball-img {
  animation: slotDropIn 0.55s cubic-bezier(0.34, 1.4, 0.64, 1) forwards;
}
@keyframes slotDropIn {
  0%   { transform: translate(-50%, -180%); opacity: 0; }
  60%  { transform: translate(-50%, -25%);  opacity: 1; }
  78%  { transform: translate(-50%,   2%);  }
  90%  { transform: translate(-50%, -10%);  }
  100% { transform: translate(-50%,   0%);  opacity: 1; }
}

/* ─── Transit ball ────────────────────────────────────────────── */
.transit-ball {
  position: absolute;
  border-radius: 50%; overflow: hidden; pointer-events: none; z-index: 5;
}
.transit-ball img { width:100%; height:100%; object-fit:cover; border-radius:50%; }

/* ─── Metal stopper / tray ────────────────────────────────────── */
.machine-tray {
  position: absolute;
  left: 127.38px; top: 482.23px;
  width: 106.49px; height: 21.45px;
  display: block; pointer-events: none; z-index: 11;
}

/* ─── Machine shadow — single Figma image ─────────────────────
   Figma: centered at 50%+51.28px, top=576.72 on canvas.
   In machine-wrap coords: top ≈ 576.72−148.68 = 428.04 × 0.9314 ≈ 399px.
   Shadow div is 429.696px wide with -20.82% / -3.05% / -20.86% / -2.16% inset bleed. */
.machine-shadow-wrap {
  position: absolute;
  /* shadow center is +47.77px right of machine center (51.28 × 0.9314) */
  left: calc(50% + 47.77px);
  transform: translateX(-50%);
  top: 399px;
  /* Figma 429.696×121.442 scaled by 0.9314 */
  width: 400.18px;
  height: 113.12px;
  pointer-events: none;
  z-index: -1;
}
.machine-shadow-img {
  position: absolute;
  top:    -20.82%;
  left:   -2.16%;
  width:  105.21%;
  height: 141.68%;
  display: block;
}

/* ═══ CONTROL PANEL — fixed to bottom of viewport (independent of machine column) */
.cp-wrap {
  position: fixed;
  left: 50%;
  bottom: 0;
  width: 482.094px;
  height: 155.075px;
  margin-top: 0;
  z-index: 35;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, 88px);
  transition: opacity 0.7s ease,
              transform 0.85s cubic-bezier(0.22, 1, 0.36, 1);
  overflow: visible;
}
.cp-wrap.visible {
  opacity: 1;
  transform: translate(-50%, 0);
  pointer-events: auto;
}

/* Project view shrinks the control panel so the slideshow gets more
   vertical real estate. Anchoring the transform-origin to bottom-center
   keeps the smaller CP flush with the viewport bottom rather than
   floating up off the edge. Scale + translate compose into a single
   transform so the .visible state remains compatible. */
body.project-view .cp-wrap.visible {
  transform: translate(-50%, 0) scale(0.68);
  transform-origin: 50% 100%;
}

/* Background image — Figma renders it scaleY(-1), we flip in CSS */
.cp-bg {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  user-select: none;
  transform: scaleY(-1);
}

/* ─── CP screws ───────────────────────────────────────────────── */
.cp-screw {
  position: absolute;
  pointer-events: none;
  top: 6.47px;
}
.cp-screw-l { left: 87.80px; }
.cp-screw-r { left: 387.47px; }

.cp-screw-outer {
  position: absolute;
  left: 0; top: 0;
  width: 8.036px; height: 5.185px;
  display: block;
}
.cp-screw-i1 {
  position: absolute;
  left: 1.22px; top: 0.79px;
  width: 5.593px; height: 3.609px;
  display: block;
}
.cp-screw-i2 {
  position: absolute;
  left: 1.22px; top: 0.08px;
  width: 5.593px; height: 3.609px;
  display: block;
}

/* ─── Joystick ────────────────────────────────────────────────── */
/* joy-wrap positioned at CP-relative coords: bottom (base) at left=80.19, top=19.16.
   Stick extends -67.93px above CP (using overflow:visible on cp-wrap). */
.joy-wrap {
  position: absolute;
  left: 80.19px;
  top: -48.77px; /* 19.16 − 67.93 = top of stick */
  width: 114.022px;
  height: 132.817px; /* 67.93 (stick above base) + 64.887 (base) */
  cursor: grab;
  user-select: none;
}
.joy-wrap:active { cursor: grabbing; }

.joy-assembly {
  position: absolute;
  left: 29.3px; /* (109.49 − 80.19) from joy-wrap left */
  top: 0;
  width: 66.349px;
  height: 133.665px;
  transform-origin: center bottom;
  transform: rotate(0deg);
  z-index: 2;
  pointer-events: none;
  transition: transform 0.15s ease;
}
.joy-stick-img {
  width: 100%; height: 100%;
  display: block;
  pointer-events: none;
}

.joy-bottom-img {
  position: absolute;
  left: 0;
  top: 67.93px; /* base starts after stick section */
  width: 114.022px;
  height: 64.887px;
  display: block;
  pointer-events: none;
}

/* ─── Spacebar ────────────────────────────────────────────────── */
.spacebar-wrap {
  position: absolute;
  left: 218.27px;
  top: 20.58px;
}
.spacebar-outer {
  position: relative;
  width: 185.025px;
  height: 56.568px; /* includes shadow layer */
  cursor: pointer;
  user-select: none;
}
.spacebar-shadow-img {
  position: absolute;
  left: 0; top: 6.61px; /* shadow sits 6.61px below face (27.19 − 20.58) */
  width: 185.025px; height: 56.568px;
  display: block;
  z-index: 1;
}
.spacebar-face-img {
  position: absolute;
  left: 0; top: 0;
  width: 185.025px; height: 56.401px;
  display: block;
  z-index: 2;
  transition: transform 0.1s ease;
}
.spacebar-outer:active .spacebar-face-img,
.spacebar-outer.pressed .spacebar-face-img { transform: translateY(3px); }

.spacebar-label {
  position: absolute;
  z-index: 3;
  bottom: 16px; left: 50%;
  transform: translateX(-50%);
  font-family: 'UntitledSans', system-ui, sans-serif;
  font-weight: 400;
  font-size: 3.58px;
  letter-spacing: 0.04em;
  color: rgba(90,90,90,0.7);
  text-transform: uppercase;
  pointer-events: none;
  white-space: nowrap;
}

/* ═══ FOOTER NAV — pinned to Figma Landing 97:1078 ═══════════════
   Figma: resume @ x=25.33, ig.right = 30.33 from right, gap(linkedin↔ig) = 47,
   text bottom 24.81px above frame bottom. */
.footer-nav {
  position: fixed;
  bottom: calc(25px + env(safe-area-inset-bottom, 0px));
  left: 0; right: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 30px 0 25px;
  pointer-events: none;
  z-index: 50;
}
.footer-right {
  display: flex;
  align-items: center;
  gap: 47px;
}
.footer-link {
  font-family: 'EB Garamond', 'Georgia', serif;
  font-weight: 400;
  font-size: 18px;
  line-height: 1.01;
  letter-spacing: -0.2px;
  color: #b8b8b8;
  text-decoration: none;
  pointer-events: all;
  white-space: nowrap;
}

/* ═══ PROJECT VIEW STATE ════════════════════════════════════════
   Machine slides up so Panel 2 (at machine-wrap y=372.55) pins
   to viewport y=0. Offset = -(top:127 + 372.55) = -499.55px.
════════════════════════════════════════════════════════════════ */

body.project-view .machine-cp-col,
body.lock-view    .machine-cp-col {
  transform: translateX(-50%) translateY(-499.55px);
}

body.project-view .machine-shadow-wrap,
body.lock-view    .machine-shadow-wrap {
  opacity: 0;
  transition: opacity 0.32s ease;
}

/* Project view keeps the control panel visible so the joystick + spacebar
   continue to drive the slideshow (joystick = prev/next, spacebar = exit
   back to home). Only the lock view still slides it offscreen — typing
   the password takes over there. */
body.lock-view .cp-wrap {
  transform: translate(-50%, 220px);
  opacity: 0;
  pointer-events: none;
}

/* Home-view bio + © copy hide; project-view intro + rights show
   (Figma 128:2676 / 128:2677). */
body.project-view .bio-text,
body.project-view .copyright-line,
body.lock-view .bio-text,
body.lock-view .copyright-line {
  opacity: 0;
  visibility: hidden;
}

/* ─── Project-view top text ─────────────────────────────────── */
.proj-intro,
.proj-rights {
  position: fixed;
  top: 14px;
  z-index: 40;
  font-family: 'EB Garamond', 'Georgia', serif;
  font-weight: 400;
  font-size: 18px;
  line-height: 1.15;
  letter-spacing: -0.18px;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.55s ease 0.15s, visibility 0.55s ease 0.15s;
}
.proj-intro {
  left: 24.5px;
  max-width: 540px;
  color: #f7f7f7;
}
.proj-rights {
  right: 14px;
  max-width: min(360px, 42vw);
  text-align: right;
  color: #a2a2a2;
}
body.project-view .proj-intro,
body.project-view .proj-rights,
body.lock-view .proj-intro,
body.lock-view .proj-rights {
  opacity: 1;
  visibility: visible;
}

/* ─── Project horizontal list ────────────────────────────────────
   Fixed full-viewport overlay. Inactive items render as circular
   thumbnails (object-cover crop); the active item morphs into a rounded
   rectangle whose width tracks the image's natural aspect ratio. The
   inner .proj-hlist-scroller translates X so the active item is parked
   at the horizontal center of the viewport — a single CSS transform +
   per-item width/height/border-radius transitions create the fluid
   shrink/grow + scroll choreography on every selection change. */
.proj-hlist {
  position: fixed;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  overflow: hidden;
  opacity: 0;
  transition: opacity 0.45s ease 0.35s;
}
body.project-view .proj-hlist {
  opacity: 1;
  pointer-events: auto;
}

.proj-hlist-scroller {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translate(0, -50%);
  display: flex;
  flex-direction: row;
  align-items: center;
  /* Justified filmstrip (Figma 223:1720): items butt edge-to-edge with no
     gap. JS centering math uses HITEM_GAP = 0 to match. */
  gap: var(--hlist-gap, 0px);
  will-change: transform;
  transition: transform 0.6s cubic-bezier(0.22, 0.7, 0.18, 1);
  transform-origin: 50% 50%;
}

.proj-hitem {
  position: relative;
  width: var(--hitem-inactive, 589px);
  height: var(--hitem-inactive, 314px);
  /* Cascade frames — width/height set inline by JS (active largest, the
     rest fan out smaller). A very small constant corner radius keeps the
     pre-composed card borders crisp without rounding into a thumbnail. */
  border-radius: 4px;
  overflow: hidden;
  /* No container background: PNGs with transparency (e.g. the Apple
     basketball, the Google G, the play button) would otherwise show a
     dark halo behind their alpha pixels, reading like a drop shadow.
     Per-slide `bg` overrides (set in PROJECTS data, e.g. fun-4 over
     #000) are still honored via inline style. */
  background: transparent;
  cursor: pointer;
  user-select: none;
  -webkit-user-drag: none;
  flex: 0 0 auto;
  will-change: width, height;
  /* Discrete morph: inactive (circle) ⇄ active (rounded rect). border-radius
     is tweened too so the circle "unrolls" into a rectangle. */
  transition:
    width 0.6s cubic-bezier(0.22, 0.7, 0.18, 1),
    height 0.6s cubic-bezier(0.22, 0.7, 0.18, 1),
    border-radius 0.6s cubic-bezier(0.22, 0.7, 0.18, 1),
    opacity 0.4s ease;
}
.proj-hitem img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
  user-select: none;
}
/* Active state — largest frame, centered. Same small radius as the rest
   so the cascade reads as one consistent set of cards. */
.proj-hitem.is-active {
  cursor: default;
  border-radius: 4px;
}
/* Inactive thumbs animate slightly on hover so it's obvious they're
   clickable (joystick navigation works the same way, but mouse users
   need a visible affordance). The lift is intentionally subtle so it
   doesn't compete with the active slide. */
.proj-hitem:not(.is-active) {
  transition:
    width 0.6s cubic-bezier(0.22, 0.7, 0.18, 1),
    height 0.6s cubic-bezier(0.22, 0.7, 0.18, 1),
    border-radius 0.6s cubic-bezier(0.22, 0.7, 0.18, 1),
    opacity 0.4s ease,
    transform 0.22s ease;
}
.proj-hitem:not(.is-active):hover {
  opacity: 1;
  transform: translateY(-3px) scale(1.05);
}

/* ─── Project caption — Figma 207:229 ─────────────────────────────
   Single-line description shown directly under the active image.
   Position is set inline by JS (top = active image's bottom + 18px)
   so it tracks the morph between slides. */
.proj-caption {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  z-index: 6;
  margin: 0;
  font-family: 'EB Garamond', 'Georgia', serif;
  font-weight: 400;
  font-size: 15px;
  line-height: 1.15;
  letter-spacing: -0.15px;
  color: #7f7f7f;
  text-align: center;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.45s ease 0.35s, visibility 0.45s ease 0.35s,
              top 0.6s cubic-bezier(0.22, 0.7, 0.18, 1);
}
body.project-view .proj-caption {
  opacity: 1;
  visibility: visible;
}

/* ─── Pagination dots — Figma 207:209 ─────────────────────────────
   Row of small dots below the caption, one per slide. The active dot
   reads brighter. Hidden entirely when a project has only one image
   (JS toggles aria-hidden + .is-hidden). */
.proj-dots {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  z-index: 6;
  display: flex;
  gap: 6px;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.45s ease 0.35s, visibility 0.45s ease 0.35s,
              top 0.6s cubic-bezier(0.22, 0.7, 0.18, 1);
}
body.project-view .proj-dots:not(.is-hidden) {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}
.proj-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #3a3a3a;
  border: 0;
  padding: 0;
  margin: 0 2px;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.2s ease;
}
.proj-dot:hover { background: #6a6a6a; }
.proj-dot.is-active {
  background: #b8b8b8;
}
.proj-dot:focus-visible {
  outline: 1px solid #777;
  outline-offset: 2px;
}

/* ─── Close button — Figma 128:2852 ───
   In project view the control panel stays visible (the spacebar is the
   primary "exit" action). The close text sits just above the shrunken
   CP so it doesn't get covered by the joystick / spacebar; the
   lock-view branch below moves it back down to its original position
   since the CP slides off-canvas there. */
.proj-close {
  position: fixed;
  left: 50%;
  bottom: calc(120px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 50;
  background: transparent;
  border: 0;
  padding: 4px 8px;
  font-family: 'EB Garamond', 'Georgia', serif;
  font-weight: 400;
  font-size: 18px;
  letter-spacing: -0.18px;
  color: #5a5a5a;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.5s ease 0.25s, visibility 0.5s ease 0.25s, color 0.2s ease;
}
body.project-view .proj-close {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}
.proj-close:hover { color: #b8b8b8; }
.proj-close:focus-visible { outline: 1px solid #777; outline-offset: 2px; }

/* Close button stays visible during the lock state too, so the user can
   back out of the password prompt without entering anything. Figma
   158:3328 renders the label "CLOSE" — uppercase, EB Garamond Medium.
   Since the CP slides off-canvas in lock-view, the close button can
   return to its original near-bottom resting position. */
body.lock-view .proj-close {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  text-transform: uppercase;
  font-weight: 400;
  color: #5a5a5a;
  bottom: calc(25px + env(safe-area-inset-bottom, 0px));
}

/* ─── Password gate — Figma 158:3328 ───────────────────────────────
   Full-viewport overlay that sits where the slideshow renders. The
   machine slides up (via body.lock-view) leaving only Panel 2 visible
   at the top of the page; the lock icon + prompt + dark input field fade
   in centered below. Default transition is a fast fade-out (no delay) so
   that the UI snaps closed on unlock; the `.lock-view` state below
   overrides with a delayed fade-IN so the prompt only appears AFTER the
   machine has slid up. */
.proj-lock {
  position: fixed;
  inset: 0;
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* Figma 168:3591 — gap between LOCK and prompt block */
  gap: 46px;
  padding: 0 24px;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.28s ease, visibility 0.28s ease;
}
body.lock-view .proj-lock {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.45s ease 0.35s, visibility 0.45s ease 0.35s;
}

/* Chrome padlock icon — exported from Figma 168:3570 at native 73×93.
   Rendered slightly larger (CSS scaled) so the proportions read as in
   the design, with crisp-edges hint to soften the bitmap upscale. */
.proj-lock-icon {
  width: 72px;
  height: auto;
  display: block;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* Inner stack — prompt text on top, input field below.
   Figma 168:3590 — w=216px, gap=18px */
.proj-lock-stack {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 18px;
  width: 216px;
  max-width: 90vw;
}

.proj-lock-prompt {
  margin: 0;
  font-family: 'EB Garamond', 'Georgia', serif;
  font-weight: 400;
  font-size: 12px;
  letter-spacing: -0.12px;
  color: #5a5a5a;
  text-align: center;
  line-height: 1.18;
  user-select: none;
}

/* Dark input field (Figma 168:3569) — 36px tall, 2px radius, 0.6px border,
   #0b0b0b fill. Cursor + typed bullets sit inside, left-aligned with
   21px horizontal padding. */
.proj-lock-input {
  display: flex;
  align-items: center;
  height: 36px;
  padding: 0 21px;
  background: #0b0b0b;
  border: 0.6px solid #000;
  border-radius: 2px;
  font-family: 'EB Garamond', 'Georgia', serif;
  font-weight: 400;
  font-size: 12px;
  letter-spacing: -0.12px;
  color: #5a5a5a;
  transition: transform 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}

.proj-lock-text {
  white-space: pre;
  letter-spacing: 2.5px;
}

.proj-lock-cursor {
  display: inline-block;
  margin-left: 0;
  font-weight: 400;
  font-size: 14px;
  line-height: 1;
  color: #5a5a5a;
  animation: lockCaret 1.05s steps(1, end) infinite;
}
@keyframes lockCaret {
  0%, 49%  { opacity: 1; }
  50%, 99% { opacity: 0; }
}

/* Wrong-password feedback: brief shake + red tint, then settle back. */
.proj-lock-input.is-wrong {
  color: #b34040;
  border-color: rgba(179, 64, 64, 0.45);
  animation: lockShake 0.42s cubic-bezier(.36,.07,.19,.97) both;
}
.proj-lock-input.is-wrong .proj-lock-cursor { color: #b34040; }
@keyframes lockShake {
  10%, 90% { transform: translate3d(-1px, 0, 0); }
  20%, 80% { transform: translate3d( 2px, 0, 0); }
  30%, 50%, 70% { transform: translate3d(-4px, 0, 0); }
  40%, 60% { transform: translate3d( 4px, 0, 0); }
}

/* ═══════════════════════════════════════════════════════════════════
   MOBILE — portrait phones (Figma 226:2439 home / 226:2871 project).
   Reuses the full desktop DOM + JS: the machine and control panel are
   just scaled down (transform, so the claw/ball/slideshow JS keeps
   working in unscaled local coordinates) and repositioned. Footer links
   rotate up the screen edges; the © lines, rights line and close text are
   dropped, and the spacebar reads ESC — matching the mobile frames.
   --m-scale / --m-top tune the machine; --cp-scale tunes the panel.
═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  :root {
    --m-scale: 0.9;
    --m-top: 150px;
    --cp-scale: 0.86;
  }

  /* Machine column — centered, scaled from its top edge so it parks just
     below the bio while the joystick stays pinned to the bottom. */
  .machine-cp-col {
    top: var(--m-top);
    transform-origin: top center;
    transform: translateX(-50%) scale(var(--m-scale));
  }
  /* Project / lock view: slide the (scaled) machine fully off the top so
     the image cascade owns the screen. translateY is in actual px (it sits
     before scale() in the list, so it isn't divided by the scale). */
  body.project-view .machine-cp-col,
  body.lock-view .machine-cp-col {
    transform: translateX(-50%) translateY(-640px) scale(var(--m-scale));
  }

  /* Control panel — pinned to the bottom, scaled from bottom-center so it
     hugs the viewport edge. Same scale in home + project view. */
  .cp-wrap.visible,
  body.project-view .cp-wrap.visible {
    transform-origin: bottom center;
    transform: translate(-50%, 0) scale(var(--cp-scale));
  }

  /* Bio (home, Figma 226:2606) and project intro (Figma 226:3053) share
     the same top slot, full width with side gutters. */
  .bio-text,
  .proj-intro {
    top: 86px;
    left: 24px;
    right: 24px;
    max-width: none;
    font-size: 16px;
  }

  /* Mobile frames drop the © lines, the rights line and the close text —
     the rotated edge links + the ESC spacebar cover all navigation. */
  .copyright-line,
  .proj-rights,
  .proj-close {
    display: none !important;
  }

  /* Footer links climb the screen edges, reading bottom-to-top:
     "resume" on the left (Figma 226:2608), "linkedin" above "ig" on the
     right (226:2610 / 226:2611). */
  #linkResume,
  .footer-right .footer-link {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    font-size: 15px;
  }
  #linkResume {
    position: fixed;
    left: 6px;
    top: 50%;
    transform: translateY(-50%) rotate(180deg);
  }
  .footer-right {
    position: fixed;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    flex-direction: column;
    align-items: center;
    gap: 22px;
  }

  /* Spacebar reads ESC (Figma 226:2602): font-size:0 collapses the
     "SPACE BAR" glyphs, ::after re-adds ESC, still centered by the span's
     own translateX(-50%). */
  .spacebar-label { font-size: 0; }
  .spacebar-label::after {
    content: "ESC";
    font-size: 3.58px;
    letter-spacing: 0.04em;
  }
}
