/* =========================================================
   Game Art Portfolio
   ========================================================= */
:root {
  --paper: #efeeea;
  --ink: #2a2c36;
  --ink-soft: #4a4d5a;
  --muted: #8a8c96;

  --d3-bg: #0b0c11;
  --d3-ink: #ecebf2;
  --d3-muted: #8f91a3;
  --d3-accent: #ffb454;

  --d2-bg: #fbf4e6;
  --d2-ink: #2b2433;
  --d2-accent: #ff5d73;
  --d2-accent2: #3fb8af;

  --ease: cubic-bezier(.2, .8, .2, 1);
  --font: "Outfit", system-ui, sans-serif;
}

* { box-sizing: border-box; }
html, body { margin: 0; }
html { overflow-x: clip; overscroll-behavior: none; }   /* no rubber-band bounce at the ends of the page */
body {
  font-family: var(--font);
  background: var(--paper);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}
/* only <html> clips sideways: an overflow value on <body> would turn it into a scroll box and break the pinned hero */
html.in-world { overflow: hidden; }
button { font: inherit; color: inherit; cursor: pointer; }
img { display: block; }
[hidden] { display: none !important; }

/* =========================================================
   TOP NAV
   ========================================================= */
.topnav {
  position: fixed; z-index: 60; top: 16px; left: 50%;
  transform: translate(-50%, -140%);
  display: flex; align-items: center; gap: 6px;
  padding: 6px;
  border-radius: 999px;
  background: rgba(20, 21, 28, .72);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  box-shadow: 0 8px 30px rgba(0,0,0,.25), inset 0 0 0 1px rgba(255,255,255,.08);
  color: #fff;
  transition: transform .6s var(--ease), background .4s;
  max-width: calc(100vw - 24px);
}
body.nav-on .topnav { transform: translate(-50%, 0); }
body.view-w2d .topnav { background: rgba(43, 36, 51, .82); }
.topnav button { border: 0; background: none; }
.brand {
  font-weight: 900; font-size: 15px; letter-spacing: .02em;
  width: 40px; height: 40px; border-radius: 50%;
  background: #fff !important; color: #16171d !important;
}
.brand span { color: var(--d2-accent); }
.pills { display: none; gap: 2px; }
body.view-home .pills[data-for="home"],
body.view-w3d .pills[data-for="w3d"],
body.view-w2d .pills[data-for="w2d"] { display: flex; }
.pills button {
  padding: 10px 16px; border-radius: 999px; font-size: 14px; font-weight: 500;
  color: rgba(255,255,255,.7); white-space: nowrap;
  transition: background .25s, color .25s;
}
.pills button:hover { color: #fff; background: rgba(255,255,255,.08); }
.pills button.active { color: #16171d; background: #fff; }
.switch { display: flex; gap: 2px; padding-left: 6px; margin-left: 2px; border-left: 1px solid rgba(255,255,255,.14); }
.sw {
  width: 40px; height: 40px; border-radius: 50%;
  font-weight: 800; font-size: 13px; color: rgba(255,255,255,.75);
  transition: background .25s, color .25s;
}
.sw:hover { background: rgba(255,255,255,.1); color: #fff; }
body.view-w3d .sw-3d { background: var(--d3-accent); color: #1b1305; }
body.view-w2d .sw-2d { background: var(--d2-accent); color: #fff; }

/* =========================================================
   HERO (samurai) + light-out transition
   ========================================================= */
.hero-wrap { height: 280vh; position: relative; background: #0d0506; }
.hero-sticky { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; }
.hero-sticky .sh-hero { height: 100%; }

.sh-glow {
  position: absolute; z-index: 5; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  font-family: "Inter", "Helvetica Neue", Arial, sans-serif;
  font-weight: 800; line-height: 1; letter-spacing: .01em; white-space: nowrap;
  color: #fff8ec;
  opacity: 0;
  pointer-events: none; user-select: none;
  mix-blend-mode: screen;
  will-change: opacity, filter, transform;
}
.sh-bloom {
  position: absolute; z-index: 6; left: 50%; top: 50%;
  width: 60vmax; height: 60vmax; border-radius: 50%;
  transform: translate(-50%, -50%) scale(0);
  background: radial-gradient(closest-side, #fff 0%, rgba(255,250,238,.95) 30%, rgba(255,236,200,.55) 60%, rgba(255,220,170,0) 100%);
  pointer-events: none;
  will-change: transform, opacity;
}
.sh-whiteout {
  position: absolute; z-index: 7; inset: 0;
  background: var(--paper); opacity: 0; pointer-events: none;
}
.scroll-cue {
  position: absolute; z-index: 8; left: 50%; bottom: 28px; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  color: rgba(255,255,255,.8); font-size: 12px; letter-spacing: .3em; text-transform: uppercase;
  opacity: 0; transition: opacity 1s 3s;
}
.sh-ready .scroll-cue, .sh-static .scroll-cue { opacity: 1; }
.scroll-cue i { width: 1px; height: 44px; background: linear-gradient(rgba(255,255,255,.9), transparent); animation: cue 2s ease-in-out infinite; transform-origin: top; }
@keyframes cue { 0% { transform: scaleY(0); } 50% { transform: scaleY(1); } 100% { transform: scaleY(1); opacity: 0; } }

/* =========================================================
   INTRO (about me)
   ========================================================= */
.intro {
  position: relative;
  min-height: 100vh; min-height: 100svh;
  padding: 110px clamp(96px, 9vw, 160px) 64px;
  background: var(--paper);
  display: flex; flex-direction: column; justify-content: center;
  overflow: hidden;
}
.intro-grid {
  display: grid;
  grid-template-columns: minmax(0, .95fr) minmax(0, 1.25fr) minmax(0, .85fr);
  grid-template-areas: "photo main side" "photo contacts contacts";
  column-gap: clamp(28px, 4vw, 72px);
  row-gap: 28px;
  max-width: 1500px; margin: 0 auto; width: 100%;
}
.photo {
  grid-area: photo; position: relative;
  border-radius: 40px; overflow: hidden;
  aspect-ratio: 3 / 4.4; align-self: center;
  background: linear-gradient(160deg, #d9d6cf, #c3bfb6);
  box-shadow: 0 30px 60px -30px rgba(40, 35, 25, .45);
}
.photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 30%; z-index: 1; }
.photo-ph {
  position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  color: #8b877d; text-align: center; font-size: 14px; line-height: 1.5;
}
.photo-ph svg { width: 40%; fill: #aaa59a; }
.photo-ph code { font-size: 12px; background: rgba(255,255,255,.5); padding: 2px 8px; border-radius: 6px; }

.intro-main { grid-area: main; }
.intro-side { grid-area: side; }
.hello { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.hello h2 {
  margin: 0; font-size: clamp(64px, 8vw, 128px); font-weight: 900; letter-spacing: -.03em; line-height: .95;
}
.mascot { width: clamp(90px, 9vw, 140px); height: auto; margin-right: 4%; }
.intro .lead { font-size: clamp(16px, 1.35vw, 21px); line-height: 1.65; color: var(--ink-soft); font-weight: 400; margin: 28px 0 0; max-width: 36em; }
.intro h3 {
  margin: 48px 0 18px; font-size: clamp(26px, 2.6vw, 40px); font-weight: 900; letter-spacing: -.01em; text-transform: uppercase;
}
.intro-side h3:first-child { margin-top: 6px; }
.intro p { margin: 0 0 8px; color: var(--ink-soft); font-size: clamp(15px, 1.2vw, 19px); }
.intro p.strong { font-weight: 800; color: var(--ink); margin-top: 18px; }
.tools { display: grid; grid-template-columns: repeat(3, 64px); gap: 12px; }
.tools span {
  width: 64px; height: 64px; border-radius: 16px;
  display: grid; place-items: center;
  background: #2b2d3a; color: #e9e9f2; font-weight: 600; font-size: 26px;
  box-shadow: inset 0 -3px 0 rgba(0,0,0,.25);
  transition: transform .3s var(--ease);
}
.tools span:hover { transform: translateY(-4px) rotate(-4deg); }
.contacts {
  grid-area: contacts; list-style: none; margin: 18px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 14px 36px; align-items: center;
  font-size: 15px; color: var(--ink-soft);
}
.contacts li, .contacts a { display: flex; align-items: center; gap: 10px; }
.contacts a { color: inherit; text-decoration: none; }
.contacts a:hover { color: var(--ink); }
.contacts svg { width: 22px; height: 22px; padding: 4px; border-radius: 50%; background: var(--ink); fill: #fff; }

.reveal { opacity: 0; transform: translateY(24px); transition: opacity .9s var(--ease), transform .9s var(--ease); }
.reveal.in { opacity: 1; transform: none; }

/* side doors */
.door {
  position: absolute; z-index: 5; top: 50%;
  width: 76px; height: min(440px, 62vh);
  transform: translateY(-50%);
  border: 0; padding: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: space-between;
  overflow: hidden;
  transition: width .5s var(--ease), box-shadow .5s;
}
.door-3d {
  left: 0; border-radius: 0 38px 38px 0;
  background: radial-gradient(120% 60% at 0% 50%, #2b2536 0%, #121218 70%);
  color: #fff;
  box-shadow: 8px 0 30px -10px rgba(0,0,0,.5);
}
.door-2d {
  right: 0; border-radius: 38px 0 0 38px;
  background: linear-gradient(160deg, #ff8a70, var(--d2-accent));
  color: #fff;
  box-shadow: -8px 0 30px -10px rgba(255, 93, 115, .6);
}
.door:hover, .door:focus-visible { width: 150px; }
.door-peek { flex: 1; width: 100%; position: relative; }
.door-peek img {
  position: absolute; left: 50%; top: 50%; height: 78%; width: auto; max-width: none;
  transform: translate(-50%, -50%) scale(.55); opacity: 0;
  transition: transform .6s var(--ease), opacity .4s;
}
.door-3d .door-peek img { inset: 0; left: 0; top: 0; width: 100%; height: 100%; object-fit: cover; transform: scale(1.2); -webkit-mask-image: linear-gradient(180deg, #000 60%, transparent); mask-image: linear-gradient(180deg, #000 60%, transparent); }
.door-3d:hover .door-peek img, .door-3d:focus-visible .door-peek img { transform: scale(1); }
.door-2d .door-peek img { height: 55%; filter: drop-shadow(0 6px 10px rgba(120,20,30,.35)); }
.door:hover .door-peek img, .door:focus-visible .door-peek img { transform: translate(-50%, -50%) scale(1); opacity: 1; }
.door-label { display: flex; flex-direction: column; align-items: center; line-height: 1; padding-bottom: 10px; }
.door-label b { font-size: 34px; font-weight: 900; letter-spacing: -.02em; }
.door-label small { font-size: 12px; letter-spacing: .3em; text-transform: uppercase; opacity: .75; margin-top: 6px; }
.door-arrow {
  font-size: 22px; width: 44px; height: 44px; border-radius: 50%; margin-bottom: 18px;
  display: grid; place-items: center; background: rgba(255,255,255,.14);
}
.door-3d .door-arrow { animation: nudgeL 2.2s ease-in-out infinite; }
.door-2d .door-arrow { animation: nudgeR 2.2s ease-in-out infinite; }
@keyframes nudgeL { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(-5px); } }
@keyframes nudgeR { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(5px); } }

.explore-hint { text-align: center; margin: 56px 0 0; color: var(--muted); font-size: 14px; letter-spacing: .04em; }
.explore-hint b { color: var(--ink); }
.explore-mobile { display: none; }

/* =========================================================
   WORLDS (shared)
   ========================================================= */
#home { transition: transform .9s var(--ease), visibility 0s; }
/* shrink instead of sliding sideways (a sideways shift makes phones widen the whole page);
   once a world has slid over it, hide the home page completely so the browser stops painting it */
body.view-w3d #home, body.view-w2d #home { transform: scale(.94); visibility: hidden; transition: transform .9s var(--ease), visibility 0s .9s; }
body.view-w3d #home { transform-origin: 0 50%; }
body.view-w2d #home { transform-origin: 100% 50%; }

.world {
  position: fixed; inset: 0; z-index: 40;
  overflow-y: auto; overflow-x: hidden;
  scroll-snap-type: y mandatory;
  overscroll-behavior: contain;
  transition: transform .9s var(--ease), visibility 0s .9s;
  visibility: hidden;
  scrollbar-width: none;
}
.world::-webkit-scrollbar { display: none; }
.w3d { transform: translateX(-100%); background: var(--d3-bg); color: var(--d3-ink); }
.w2d { transform: translateX(100%); background: var(--d2-bg); color: var(--d2-ink); }
body.view-w3d .w3d, body.view-w2d .w2d { transform: none; visibility: visible; transition: transform .9s var(--ease), visibility 0s; }

.sec {
  position: relative;
  min-height: 100vh; min-height: 100svh; height: 100svh;
  scroll-snap-align: start; scroll-snap-stop: always;
  padding: 96px clamp(20px, 5vw, 80px) 84px;
  display: flex; flex-direction: column;
  overflow: hidden;
}
.sec-head { position: relative; z-index: 3; max-width: 640px; }
.kicker { margin: 0 0 8px; font-size: 13px; font-weight: 600; letter-spacing: .28em; text-transform: uppercase; opacity: .6; }
.sec-head h2, .game-info h2 { margin: 0; font-size: clamp(40px, 5.2vw, 76px); font-weight: 900; letter-spacing: -.03em; line-height: 1; }
.sub { margin: 14px 0 0; font-size: clamp(15px, 1.15vw, 18px); line-height: 1.55; opacity: .72; max-width: 36em; }

.next-cue {
  position: absolute; z-index: 6; left: 50%; bottom: 22px; transform: translateX(-50%);
  display: flex; align-items: center; gap: 8px;
  border: 0; border-radius: 999px; padding: 10px 18px 10px 20px;
  font-size: 14px; white-space: nowrap;
  background: rgba(255,255,255,.08); color: inherit;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.14);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  transition: background .25s;
}
.next-cue:hover { background: rgba(255,255,255,.16); }
.next-cue i { font-style: normal; display: inline-block; animation: bob 1.8s ease-in-out infinite; }
.next-cue.end i { animation: none; }
@keyframes bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(4px); } }
.w2d .next-cue { background: #fff; box-shadow: 0 6px 20px -8px rgba(60, 30, 40, .35), inset 0 0 0 1px rgba(43,36,51,.08); }
.w2d .next-cue:hover { background: #fff6ee; }

/* =========================================================
   3D · CHARACTER HALL
   ========================================================= */
.hall { padding: 0; }
.hall .sec-head { position: absolute; top: 96px; left: clamp(20px, 5vw, 80px); pointer-events: none; }
.hall-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; cursor: grab; }
.hall-canvas:active { cursor: grabbing; }
.hall-labels { position: absolute; inset: 0; pointer-events: none; z-index: 2; }
.hall-label {
  position: absolute; transform: translate(-50%, 0);
  pointer-events: auto; border: 0;
  padding: 8px 16px; border-radius: 999px;
  background: rgba(12, 12, 18, .65); color: #fff; font-size: 14px; font-weight: 600; white-space: nowrap;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.14);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  transition: background .25s, opacity .3s;
}
.hall-label:hover, .hall-label.on { background: var(--d3-accent); color: #1b1305; }
.hall-label small { font-weight: 400; opacity: .7; margin-left: 6px; }
.hall-card {
  position: absolute; z-index: 4; right: clamp(16px, 4vw, 64px); top: 50%; transform: translateY(-50%);
  width: min(360px, calc(100vw - 32px));
  padding: 28px; border-radius: 24px;
  background: rgba(18, 18, 26, .78);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.1), 0 30px 60px -20px rgba(0,0,0,.6);
  animation: cardIn .5s var(--ease);
}
@keyframes cardIn { from { opacity: 0; transform: translateY(-46%); } }
.hall-card h3 { margin: 0 0 10px; font-size: 34px; font-weight: 900; letter-spacing: -.02em; }
.hall-card p { margin: 0; color: var(--d3-muted); line-height: 1.55; font-size: 15px; }
.hall-card .kicker { color: var(--d3-accent); opacity: 1; font-size: 11px; margin-bottom: 8px; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 18px; }
.chips span { font-size: 12px; padding: 5px 10px; border-radius: 999px; background: rgba(255,255,255,.07); color: #d4d4de; }
.anim-toggle { display: flex; gap: 6px; margin-top: 18px; }
.anim-toggle:empty { display: none; }
.anim-toggle button {
  flex: 1; border: 0; padding: 10px; border-radius: 12px; font-weight: 600;
  background: rgba(255,255,255,.07); color: #d4d4de;
}
.anim-toggle button.on { background: var(--d3-accent); color: #1b1305; }
.x {
  position: absolute; top: 14px; right: 14px; width: 34px; height: 34px; border-radius: 50%; border: 0;
  background: rgba(255,255,255,.08); font-size: 22px; line-height: 1;
}
.hall-loading {
  position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column; gap: 14px; align-items: center; justify-content: center;
  color: var(--d3-muted); font-size: 14px; transition: opacity .6s; pointer-events: none;
}
.hall-loading i { width: 38px; height: 38px; border-radius: 50%; border: 3px solid rgba(255,255,255,.12); border-top-color: var(--d3-accent); animation: spin 1s linear infinite; }
.hall-loading.done { opacity: 0; }
@keyframes spin { to { transform: rotate(360deg); } }

/* =========================================================
   3D · RENDERS
   ========================================================= */
.renders { background: radial-gradient(90% 60% at 80% 0%, #1b1726 0%, var(--d3-bg) 60%); }
.render-grid {
  flex: 1; min-height: 0; margin-top: 28px;
  display: grid; gap: 14px;
  grid-template-columns: repeat(6, 1fr);
  grid-template-rows: repeat(2, minmax(0, 1fr));
}
.render {
  position: relative; border-radius: 18px; overflow: hidden; cursor: pointer;
  background: #16161f; border: 0; padding: 0;
  grid-column: span 2;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06);
}
.render:nth-child(1) { grid-column: span 3; }
.render:nth-child(2) { grid-column: span 3; }
.render video, .render img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.2s var(--ease), filter .6s; }
.render:hover video, .render:hover img { transform: scale(1.04); }
.render::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 55%, rgba(0,0,0,.75));
  pointer-events: none;
}
.render-cap {
  position: absolute; z-index: 1; left: 18px; right: 18px; bottom: 14px;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  text-align: left; color: #fff;
}
.render-cap b { font-size: 17px; font-weight: 700; }
.render-cap small { display: block; font-size: 12px; opacity: .6; margin-top: 2px; }
.render-cap .open {
  flex: none; width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center;
  background: rgba(255,255,255,.14); font-size: 13px; transition: background .25s;
}
.render:hover .open { background: var(--d3-accent); color: #1b1305; }

.lightbox {
  position: fixed; inset: 0; z-index: 80; background: rgba(5,5,8,.94);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 60px 24px 24px;
  animation: fade .3s;
}
@keyframes fade { from { opacity: 0; } }
.lightbox .x { color: #fff; top: 20px; right: 20px; width: 44px; height: 44px; }
.lb-media { width: min(1400px, 100%); max-height: calc(100vh - 140px); display: flex; justify-content: center; }
.lb-media video, .lb-media img { max-width: 100%; max-height: calc(100vh - 140px); border-radius: 12px; background: #000; }
.lb-title { color: #ddd; margin: 0; font-weight: 600; }

/* =========================================================
   GAMES
   ========================================================= */
.game { justify-content: center; }
.craft { background: radial-gradient(80% 70% at 20% 100%, #1a2419 0%, var(--d3-bg) 65%); }
.platformer { background: linear-gradient(180deg, #bfe7ff 0%, #e8f6ff 55%, var(--d2-bg) 100%); }
.game-layout {
  display: grid; grid-template-columns: minmax(240px, 340px) 1fr; gap: clamp(24px, 4vw, 56px);
  align-items: center; flex: 1; min-height: 0;
}
.keys { list-style: none; padding: 0; margin: 28px 0 0; display: grid; gap: 10px; font-size: 14px; opacity: .85; }
.keys li { display: flex; align-items: center; gap: 5px; }
kbd {
  font-family: inherit; font-size: 12px; font-weight: 600; min-width: 28px; height: 28px; padding: 0 8px;
  display: inline-grid; place-items: center; border-radius: 7px;
  background: rgba(255,255,255,.1); box-shadow: inset 0 -2px 0 rgba(0,0,0,.35), inset 0 0 0 1px rgba(255,255,255,.12);
}
.w2d kbd { background: #fff; box-shadow: inset 0 -2px 0 rgba(43,36,51,.18), inset 0 0 0 1px rgba(43,36,51,.12); }
.game-frame {
  position: relative; width: 100%; max-height: 100%; aspect-ratio: 16 / 9;
  border-radius: 22px; overflow: hidden; justify-self: center;
  background: #000 center / cover no-repeat;
  box-shadow: 0 40px 80px -30px rgba(0,0,0,.6), inset 0 0 0 1px rgba(255,255,255,.08);
}
.craft .game-frame { background-image: linear-gradient(rgba(10,12,10,.45), rgba(10,12,10,.7)), url("../games/godotcraft/index.png"); background-color: #1d2a1c; }
.platformer .game-frame { background-image: linear-gradient(rgba(20,30,50,.25), rgba(20,30,50,.55)), url("../games/platformer/index.png"); background-color: #3a6ea5; box-shadow: 0 40px 80px -30px rgba(40,60,90,.55); }
.game-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; background: #000; }
.play {
  position: absolute; inset: 0; border: 0; background: none; color: #fff;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
}
.play-ico {
  width: 86px; height: 86px; border-radius: 50%; display: grid; place-items: center; font-size: 30px; padding-left: 6px;
  background: rgba(255,255,255,.16); box-shadow: inset 0 0 0 2px rgba(255,255,255,.5);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  transition: transform .35s var(--ease), background .3s;
}
.play:hover .play-ico { transform: scale(1.08); background: rgba(255,255,255,.28); }
.play b { font-size: 22px; font-weight: 800; }
.play small { opacity: .7; font-size: 13px; }
.fs {
  position: absolute; z-index: 2; right: 12px; bottom: 12px; width: 40px; height: 40px; border: 0; border-radius: 10px;
  background: rgba(0,0,0,.55); color: #fff; font-size: 20px;
}

/* =========================================================
   2D · FEATURED CHARACTERS
   ========================================================= */
.featured {
  background:
    radial-gradient(60% 40% at 50% 100%, #ffe1c4 0%, transparent 70%),
    var(--d2-bg);
}
.featured::before { /* dotted backdrop */
  content: ""; position: absolute; inset: 0; opacity: .5;
  background-image: radial-gradient(rgba(43,36,51,.13) 1.4px, transparent 1.6px);
  background-size: 26px 26px;
  mask-image: linear-gradient(180deg, transparent, #000 30%, #000 70%, transparent);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 30%, #000 70%, transparent);
}
.featured .sec-head { text-align: center; margin: 0 auto; }
.featured .sub { margin-inline: auto; }
.stage {
  position: relative; z-index: 2; flex: 1; min-height: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(8px, 3vw, 48px);
  align-items: end; max-width: 1280px; width: 100%; margin: 0 auto; padding-bottom: 36px;
}
.hero-char {
  position: relative; border: 0; background: none; padding: 0;
  display: flex; flex-direction: column; align-items: center;
  height: 100%; justify-content: flex-end;
}
.hero-char .pedestal {
  position: absolute; bottom: 70px; left: 50%; transform: translateX(-50%);
  width: 72%; height: 44px; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(43,36,51,.22), transparent);
}
.hero-char .blob {
  position: absolute; bottom: 90px; left: 50%; transform: translateX(-50%) scale(.9);
  width: 78%; aspect-ratio: 1; border-radius: 46% 54% 50% 50% / 55% 48% 52% 45%;
  background: var(--c); opacity: .14;
  transition: transform .6s var(--ease), opacity .4s, border-radius 1.2s;
}
.hero-char:hover .blob { transform: translateX(-50%) scale(1); opacity: .24; border-radius: 55% 45% 42% 58% / 45% 55% 45% 55%; }
.hero-char img {
  position: relative; width: min(100%, 44vh); height: auto; margin-bottom: 36px;
  transition: transform .5s var(--ease);
}
.hero-char:hover img { transform: translateY(-10px) scale(1.04); }
.hero-char .tag {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 2px;
}
.hero-char .tag b { font-size: clamp(20px, 2vw, 28px); font-weight: 900; }
.hero-char .tag small { font-size: 13px; opacity: .6; }
.hero-char .tag em {
  font-style: normal; font-size: 13px; font-weight: 600; margin-top: 10px;
  padding: 7px 14px; border-radius: 999px; background: var(--d2-ink); color: #fff;
  opacity: 0; transform: translateY(6px); transition: opacity .3s, transform .3s var(--ease);
}
.hero-char:hover .tag em, .hero-char:focus-visible .tag em { opacity: 1; transform: none; }

/* full character page */
.char-page {
  position: fixed; inset: 0; z-index: 50;
  background: var(--d2-bg);
  overflow-y: auto;
  padding: 88px clamp(20px, 5vw, 80px) 48px;
  animation: pageIn .6s var(--ease);
}
.char-page.closing { animation: pageOut .45s var(--ease) forwards; }
@keyframes pageIn { from { opacity: 0; transform: translateY(40px); } }
@keyframes pageOut { to { opacity: 0; transform: translateY(40px); } }
.char-page .back {
  position: fixed; z-index: 3; left: clamp(16px, 3vw, 40px); top: 84px;
  border: 0; border-radius: 999px; padding: 10px 18px; font-weight: 600; font-size: 14px;
  background: #fff; box-shadow: 0 6px 20px -8px rgba(60, 30, 40, .35), inset 0 0 0 1px rgba(43,36,51,.08);
}
.char-body { max-width: 1320px; margin: 0 auto; }

/* shared character detail (page + modal) */
.cd-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; flex-wrap: wrap; margin-bottom: 26px; }
.cd-head h2 { margin: 0; font-size: clamp(40px, 5vw, 72px); font-weight: 900; letter-spacing: -.03em; line-height: 1; }
.cd-head .role { display: inline-block; margin-bottom: 10px; font-size: 12px; font-weight: 700; letter-spacing: .2em; text-transform: uppercase; padding: 5px 10px; border-radius: 999px; background: var(--c); color: #fff; }
.cd-head p { margin: 12px 0 0; max-width: 34em; line-height: 1.55; opacity: .72; }
.cd-count { font-size: 14px; opacity: .6; }
.anims { display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr)); gap: 16px; }
.anim {
  position: relative; margin: 0; border-radius: 22px; overflow: hidden;
  background:
    linear-gradient(45deg, rgba(43,36,51,.045) 25%, transparent 25%, transparent 75%, rgba(43,36,51,.045) 75%) 0 0 / 28px 28px,
    linear-gradient(45deg, rgba(43,36,51,.045) 25%, transparent 25%, transparent 75%, rgba(43,36,51,.045) 75%) 14px 14px / 28px 28px,
    #fff;
  box-shadow: 0 10px 30px -18px rgba(60, 30, 40, .4), inset 0 0 0 1px rgba(43,36,51,.06);
}
.anim img { width: 100%; aspect-ratio: 1; object-fit: contain; padding: 6%; }
.anim figcaption {
  position: absolute; left: 14px; top: 14px; display: flex; gap: 6px; align-items: center;
  font-size: 13px; font-weight: 700;
}
.anim figcaption span { padding: 5px 11px; border-radius: 999px; background: var(--d2-ink); color: #fff; }
.anim figcaption i { font-style: normal; font-weight: 500; opacity: .5; }
.anim.action figcaption span { background: var(--c); }

.sheets { margin-top: 28px; }
.sheet-tabs { display: flex; gap: 6px; margin-bottom: 14px; flex-wrap: wrap; }
.sheet-tabs button {
  border: 0; border-radius: 999px; padding: 9px 16px; font-size: 14px; font-weight: 600;
  background: rgba(43,36,51,.07);
}
.sheet-tabs button.on { background: var(--d2-ink); color: #fff; }
.sheet-view {
  border-radius: 22px; background: #fff; padding: clamp(12px, 2vw, 28px);
  box-shadow: 0 10px 30px -18px rgba(60, 30, 40, .4), inset 0 0 0 1px rgba(43,36,51,.06);
  display: flex; justify-content: center;
}
.sheet-view img { max-width: 100%; max-height: 72vh; width: auto; height: auto; }
.sheet-view.parts img { max-height: 64vh; }

/* =========================================================
   2D · STICKER BOOK
   ========================================================= */
.stickers { background: #e9dcc4; padding-top: 88px; }
.book {
  position: relative; flex: 1; min-height: 0; width: 100%; max-width: 1400px; margin: 0 auto;
  border-radius: 10px 26px 26px 10px;
  background:
    linear-gradient(90deg, rgba(0,0,0,.08) 0, transparent 26px),
    repeating-linear-gradient(0deg, transparent 0 31px, rgba(63, 184, 175, .16) 31px 32px),
    #fffaf0;
  box-shadow: 0 30px 60px -30px rgba(70, 45, 20, .55), 0 2px 0 #f3e7cf, 0 4px 0 #eadcc0, 0 6px 0 #e0cfae;
  display: flex; flex-direction: column;
}
.book::before { /* margin line */
  content: ""; position: absolute; top: 0; bottom: 0; left: 72px; width: 2px; background: rgba(255, 93, 115, .35);
}
.book-head { position: relative; z-index: 2; padding: 22px 32px 0 100px; display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap; }
.book-head h2 { margin: 0; font-family: "Caveat", cursive; font-size: clamp(44px, 5vw, 72px); font-weight: 700; line-height: 1; color: var(--d2-ink); transform: rotate(-2deg); }
.book-head p { margin: 0; font-family: "Caveat", cursive; font-size: 24px; color: var(--d2-accent); }
.sticker-field { position: relative; flex: 1; min-height: 0; margin: 0 24px 16px 84px; }
.sticker {
  position: absolute; border: 0; padding: 0; background: none;
  width: calc(var(--s) * 1%); aspect-ratio: 1;
  transform: rotate(calc(var(--r) * 1deg));
  transition: transform .45s var(--ease);
  animation: stickIn .7s var(--ease) both;
  animation-delay: calc(var(--i) * 80ms);
}
.sticker img {
  width: 100%; height: 100%; object-fit: contain;
  /* white die-cut border + soft drop shadow */
  filter:
    drop-shadow(3px 0 0 #fff) drop-shadow(-3px 0 0 #fff) drop-shadow(0 3px 0 #fff) drop-shadow(0 -3px 0 #fff)
    drop-shadow(0 8px 10px rgba(70, 45, 20, .25));
}
.sticker:hover, .sticker:focus-visible { transform: rotate(0deg) scale(1.08); z-index: 3; }
.sticker .name {
  position: absolute; left: 50%; bottom: -4px; transform: translateX(-50%) rotate(calc(var(--r) * -1deg));
  font-family: "Caveat", cursive; font-size: 22px; font-weight: 700; white-space: nowrap; color: var(--d2-ink);
  opacity: 0; transition: opacity .3s;
}
.sticker:hover .name, .sticker:focus-visible .name { opacity: 1; }
.sticker .tape {
  position: absolute; top: 2%; left: 50%; width: 34%; height: 11%; transform: translateX(-50%) rotate(-4deg);
  background: rgba(255, 234, 170, .7); box-shadow: 0 1px 2px rgba(0,0,0,.08);
}
@keyframes stickIn { from { opacity: 0; transform: rotate(calc(var(--r) * 1deg + 20deg)) scale(.6); } }

/* modal */
.modal {
  position: fixed; inset: 0; z-index: 70; display: flex; align-items: center; justify-content: center;
  padding: 20px; background: rgba(43, 36, 51, .55);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  animation: fade .3s;
}
.modal-card {
  position: relative; width: min(1180px, 100%); max-height: calc(100vh - 40px); overflow-y: auto;
  border-radius: 28px; background: var(--d2-bg); color: var(--d2-ink);
  padding: clamp(20px, 3vw, 40px);
  box-shadow: 0 40px 80px -20px rgba(0,0,0,.45);
  animation: pop .45s var(--ease);
}
@keyframes pop { from { opacity: 0; transform: translateY(30px) scale(.96); } }
.modal .x { background: rgba(43,36,51,.08); color: var(--d2-ink); top: 18px; right: 18px; }
.modal .cd-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; align-items: start; }
.modal .cd-body.single { grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); }
.modal .cd-body.single .sheets { margin-top: 0; }
.modal .sheet-view img { max-height: 46vh; }

/* =========================================================
   RESPONSIVE
   ========================================================= */
@media (max-width: 1100px) {
  .intro { padding-inline: 88px; }
  .intro-grid { grid-template-columns: minmax(0, .9fr) minmax(0, 1.3fr); grid-template-areas: "photo main" "side side" "contacts contacts"; }
  .intro-side { display: grid; grid-template-columns: auto 1fr; column-gap: 48px; }
  .intro-side h3 { grid-column: 1 / -1; }
  .render-grid { grid-template-columns: repeat(2, 1fr); grid-template-rows: none; grid-auto-rows: minmax(0, 1fr); }
  .render, .render:nth-child(1), .render:nth-child(2) { grid-column: span 1; }
  .render:nth-child(1) { grid-column: span 2; }
  .modal .cd-body, .modal .cd-body.single { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
  .pills button { padding: 9px 11px; font-size: 13px; }
  body.view-home .pills[data-for="home"] { display: none; }
  .topnav { top: 10px; }
  .door { display: none; }
  .explore-mobile { display: flex; gap: 10px; margin-top: 36px; }
  .explore-mobile button { flex: 1; border: 0; padding: 16px; border-radius: 18px; font-weight: 800; font-size: 17px; color: #fff; }
  .explore-mobile button:first-child { background: #16161d; }
  .explore-mobile button:last-child { background: var(--d2-accent); }
  .explore-hint { display: none; }
  .intro { padding: 96px 16px 48px; }
  .intro-grid { grid-template-columns: 1fr; grid-template-areas: "photo" "main" "side" "contacts"; }
  .photo { aspect-ratio: 4 / 4.2; max-width: 420px; }
  .intro-side { display: block; }
  .sec { padding: 84px 16px 76px; height: auto; min-height: 100svh; }
  .hall { height: 100svh; padding: 0; }
  .hall .sec-head { top: 76px; left: 16px; }
  .hall-card { top: auto; bottom: 76px; transform: none; right: 16px; }
  @keyframes cardIn { from { opacity: 0; transform: translateY(20px); } }
  .render-grid { grid-template-columns: 1fr; grid-auto-rows: 200px; }
  .render:nth-child(1) { grid-column: span 1; }
  .game-layout { grid-template-columns: 1fr; }
  .stage { grid-template-columns: 1fr 1fr 1fr; gap: 4px; }
  .hero-char .tag small { display: none; }
  .anims { grid-template-columns: 1fr 1fr; }
  .book::before { left: 30px; }
  .book-head { padding-left: 46px; }
  .sticker-field { margin: 0 8px 12px 36px; min-height: 60vh; }
  .next-cue { font-size: 13px; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
.game-info h2 { font-size: clamp(36px, 3.6vw, 60px); }
.char-page { padding-top: 136px; }
.char-page .anim img { aspect-ratio: auto; height: min(40vh, 28vw); }
@media (max-width: 760px) { .char-page { padding-top: 128px; } .char-page .back { top: 70px; } .char-page .anim img { height: 38vw; } }
.modal .anim img { aspect-ratio: auto; height: min(30vh, 24vw); }
.modal .cd-body.single .anim img { height: min(48vh, 40vw); }
@media (max-width: 760px) {
  .in-world .brand { display: none; }
  .topnav { gap: 2px; padding: 5px; }
  .pills button { padding: 8px 9px; font-size: 12px; }
  .sw { width: 34px; height: 34px; font-size: 12px; }
  .sticker-field { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 12px; align-content: start; margin: 12px 12px 16px 40px; min-height: 0; }
  .sticker { position: relative; left: auto !important; top: auto !important; width: 100%; }
  .sticker .name { opacity: 1; font-size: 18px; }
  .stickers { height: auto; }
}
@media (max-width: 760px) { .sticker .name { bottom: -16px; } }
@media (max-width: 760px) { .hall-label { font-size: 12px; padding: 6px 11px; } .hall-label small { display: none; } }

/* =========================================================
   v2: pinned hero -> light fills the screen -> intro spawns on top
   ========================================================= */
.hero-wrap { height: 360vh; }
.intro {
  position: absolute; inset: 0; z-index: 10;
  min-height: 0; height: 100%;
  background: transparent;
  overflow-y: auto; overscroll-behavior: contain;
  visibility: hidden; pointer-events: none;
  padding: 96px clamp(150px, 11vw, 180px) 40px;
  justify-content: flex-start;
  scrollbar-width: none;
}
.intro::-webkit-scrollbar { display: none; }
.intro.show { visibility: visible; pointer-events: auto; }
.intro { overflow: hidden; }
.intro.scrolls { overflow-y: auto; }
.intro-grid { margin-block: auto; transform-origin: 50% 0; }

.spawn {
  opacity: 0;
  transform: translateY(28px) scale(.94);
  filter: blur(10px);
  transition: opacity .7s var(--ease), transform .9s cubic-bezier(.2, 1.3, .3, 1), filter .7s var(--ease);
  transition-delay: 0s;
}
.intro.show .spawn {
  opacity: 1; transform: none; filter: none;
  transition-delay: calc(var(--d, 0) * 70ms);
}

/* two small buttons on the sides */
.side-btn {
  position: absolute; z-index: 5; top: 50%;
  display: inline-flex; align-items: center; gap: 8px;
  height: 44px; padding: 0 18px; border: 0; border-radius: 999px;
  font-weight: 700; font-size: 14px; letter-spacing: .01em;
  box-shadow: 0 8px 24px -10px rgba(0,0,0,.35);
  transition: opacity .7s var(--ease), transform .6s var(--ease), box-shadow .35s, filter .7s;
}
.side-btn i { font-style: normal; transition: transform .35s var(--ease); }
.side-3d { left: 20px; background: #16161d; color: #fff; }
.side-2d { right: 20px; background: var(--d2-accent); color: #fff; }
.side-btn.spawn { transform: translateY(-50%) scale(.85); }
.intro.show .side-btn.spawn { transform: translateY(-50%); }
.side-3d:hover i { transform: translateX(-4px); }
.side-2d:hover i { transform: translateX(4px); }
.side-btn:hover { box-shadow: 0 12px 30px -10px rgba(0,0,0,.45); }

@media (max-width: 1100px) { .intro { padding-inline: 150px; } }
@media (max-width: 900px) {
  .intro { padding-inline: 32px; padding-bottom: 96px; }
  .side-btn { top: auto; bottom: 20px; position: fixed; }
  .side-btn.spawn, .intro.show .side-btn.spawn { transform: none; }
  .side-3d { left: 16px; } .side-2d { right: 16px; }
}
@media (max-width: 760px) { .intro { padding: 84px 16px 96px; } }

/* hall: isolate card extras */
.card-label { margin: 18px 0 0 !important; font-size: 11px !important; letter-spacing: .24em; text-transform: uppercase; color: var(--d3-muted); }
.view-toggle { margin-top: 8px; }
.card-hint { margin-top: 16px !important; font-size: 12px !important; }
.card-hint kbd { height: 22px; min-width: 22px; font-size: 11px; }
.hall .sec-head, .hall .next-cue { transition: opacity .4s; }
.hall.isolated .sec-head, .hall.isolated .next-cue { opacity: 0; pointer-events: none; }
.hall.isolated .hall-canvas { cursor: grab; }

/* 2D: the viking faces the other way and matches the others' size on the stage */
/* Both states use the same list of transform functions, so the hover only animates the lift:
   a mismatched list makes the browser interpolate the mirror (negative scale) as a spin. */
.hero-char { --fx: translateY(0) scale(1, 1); }
.hero-char[data-id="viking"] { --fx: translateY(9.5%) scale(-1.27, 1.27); }
.hero-char img { transform: translateY(0) scale(1) var(--fx); transform-origin: 50% 86%; }
.hero-char:hover img { transform: translateY(-10px) scale(1.04) var(--fx); }
.anim img.flip { transform: scaleX(-1); }

/* =========================================================
   v3: isolated character scenes (from portfolio web/character-hall)
   ========================================================= */
.hall { --iso-accent: #ffb454; --iso-ink: #f4f5f8; --iso-soft: rgba(244, 245, 248, .7); }
.iso-ui { position: absolute; inset: 0; z-index: 4; pointer-events: none; font-family: "IBM Plex Mono", ui-monospace, Consolas, monospace; color: var(--iso-ink); }
.iso-top, .iso-panel { opacity: 0; transform: translateY(12px); transition: opacity .5s, transform .5s; }
.hall.isolated .iso-top, .hall.isolated .iso-panel { opacity: 1; transform: none; }
.hall.isolated .iso-top > *, .hall.isolated .iso-panel > * > *, .hall.isolated .iso-nav { pointer-events: auto; }
.iso-top { position: absolute; top: 84px; left: clamp(16px, 3vw, 24px); display: grid; justify-items: start; gap: 10px; }
.iso-drag { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--iso-soft); }
.iso-pill {
  font: 500 12px/1 "IBM Plex Mono", ui-monospace, monospace; letter-spacing: .08em; text-transform: uppercase;
  color: var(--iso-ink); background: rgba(12, 14, 20, .38); border: 1px solid rgba(255, 255, 255, .18);
  border-radius: 999px; padding: 11px 16px; cursor: pointer;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  transition: background .25s, border-color .25s, color .25s;
}
.iso-pill:hover { border-color: var(--iso-accent); }
.iso-pill:focus-visible { outline: 2px solid var(--iso-accent); outline-offset: 2px; }
.iso-pill[aria-pressed="true"] { background: var(--iso-accent); border-color: var(--iso-accent); color: #111; }
.iso-panel {
  position: absolute; left: clamp(16px, 3vw, 24px); right: clamp(16px, 3vw, 24px); bottom: max(24px, env(safe-area-inset-bottom));
  display: flex; justify-content: space-between; align-items: flex-end; gap: 20px; flex-wrap: wrap;
}
.iso-who { display: grid; gap: 8px; min-width: 0; }
.iso-kicker { font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--iso-accent); }
.iso-who h3 { margin: 0; font: 800 clamp(34px, 6vw, 64px)/.95 "Syne", "Trebuchet MS", system-ui, sans-serif; letter-spacing: -.01em; text-wrap: balance; }
.iso-made { font-size: 12px; color: var(--iso-soft); max-width: 46ch; line-height: 1.5; }
.iso-anims { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
.iso-anims:has(> :only-child) { display: none; }
.iso-nav { display: flex; gap: 8px; }
.iso-arrow { width: 44px; height: 44px; padding: 0; display: grid; place-items: center; font-size: 16px; }
.hall.isolated .hall-canvas { cursor: grab; }
.hall.isolated .hall-canvas:active { cursor: grabbing; }
@media (max-width: 620px) {
  .iso-top { top: 72px; }
  .iso-panel { flex-direction: column; align-items: stretch; }
  .iso-nav { justify-content: space-between; }
}
@media (prefers-reduced-motion: reduce) { .iso-top, .iso-panel { transition: none; } }

/* =========================================================
   v3: top nav on phones: tighter pills, and only the button for the *other* world
   ========================================================= */
@media (max-width: 480px) {
  .topnav { gap: 0; }
  .pills button { padding: 8px 8px; font-size: 11.5px; }
  .switch { padding-left: 4px; margin-left: 2px; }
  body.view-w3d .sw-3d, body.view-w2d .sw-2d { display: none; }
}

/* =========================================================
   v3: 2D on phones: characters two-up (third centred) and bigger; stickers get room for their name pills
   ========================================================= */
@media (max-width: 640px) {
  .featured { height: auto; }
  .stage { grid-template-columns: 1fr 1fr; row-gap: 12px; align-items: end; padding-top: 24px; flex: none; }
  .hero-char:nth-child(3) { grid-column: 1 / -1; justify-self: center; width: 55%; }
  .hero-char img { width: 100%; margin-bottom: 20px; }
  .hero-char .pedestal { bottom: 52px; }
  .hero-char .blob { bottom: 64px; }
  .hero-char .tag em { display: none; }
  .stickers { height: auto; }
  .sticker-field { row-gap: 44px; padding-bottom: 36px; }
}

/* characters are sized by the window height too, so their names never run into the scroll hint */
@media (min-width: 641px) {
  .hero-char img { width: min(100%, 44vh, calc(100svh - 380px)); min-width: 150px; }
  .hero-char .blob { width: min(78%, 40vh, max(140px, calc(100svh - 410px))); }
  .hero-char .pedestal { width: min(72%, 40vh, max(130px, calc(100svh - 410px))); }
}
@media (min-width: 641px) and (max-height: 780px) {
  .featured { padding-top: 80px; padding-bottom: 72px; }
  .featured .sec-head h2 { font-size: clamp(36px, 4.2vw, 56px); }
  .featured .sub { margin-top: 8px; font-size: 14px; }
  .hero-char img { margin-bottom: 26px; }
  .stage { padding-bottom: 20px; }
}

/* =========================================================
   v3: short screens (landscape phones, small laptop windows): sections grow with their content
   instead of cutting it off; the Character Hall stays one full screen
   ========================================================= */
@media (max-height: 560px) {
  .sec { height: auto; min-height: 100svh; padding-top: 76px; }
  .hall { height: 100svh; padding: 0; }
  .hall .sec-head { top: 64px; }
  .sec-head h2, .game-info h2 { font-size: clamp(30px, 4vw, 48px); }
  .sub { margin-top: 8px; }
  .stage, .render-grid, .game-layout { flex: none; }
  .hero-char img { width: min(100%, 220px); }
  .photo { width: min(100%, 52svh); justify-self: start; }
  .intro { padding-top: 72px; }
  .hello h2 { font-size: clamp(48px, 7vw, 80px); }
}

/* =========================================================
   v3: About page layout per screen size
   wide: photo | text | skills+experience, side buttons at the screen edges
   medium: photo | text, then skills and experience side by side; buttons move to the bottom corners
   phone: one column
   ========================================================= */
.intro-side h3 { grid-column: auto; }
@media (max-width: 1100px) {
  .intro { padding: 88px clamp(20px, 4vw, 40px) 96px; }
  .intro-grid {
    grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr);
    grid-template-areas: "photo main" "side side" "contacts contacts";
    row-gap: 24px; column-gap: clamp(24px, 4vw, 48px);
  }
  .photo { aspect-ratio: 3 / 4; }
  .intro-side { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: clamp(32px, 7vw, 96px); align-items: start; }
  .intro-side h3, .intro-side h3:first-child { margin-top: 0; }
  .side-btn { position: fixed; top: auto; bottom: 20px; }
  .side-btn.spawn, .intro.show .side-btn.spawn { transform: none; }
  .side-3d { left: 16px; } .side-2d { right: 16px; }
  .contacts { justify-content: center; }
  /* fade strip behind the bottom buttons so they never sit on top of text */
  .intro.show::after {
    content: ""; position: fixed; z-index: 4; left: 0; right: 0; bottom: 0; height: 88px; pointer-events: none;
    background: linear-gradient(rgba(239, 238, 234, 0), var(--paper) 60%);
  }
}
@media (max-width: 640px) {
  .intro { padding: 80px 16px 96px; }
  .intro-grid { grid-template-columns: 1fr; grid-template-areas: "photo" "main" "side" "contacts"; }
  .photo { width: min(78%, 300px); justify-self: center; aspect-ratio: 1; border-radius: 32px; }
  .intro-side { grid-template-columns: 1fr; row-gap: 8px; }
  .intro h3 { margin-top: 32px; }
  .intro-side h3:first-child { margin-top: 32px; }
  .contacts { justify-content: flex-start; gap: 12px 24px; }
}

/* =========================================================
   v3: render tiles keep the renders' own 4:3 frame (nothing cropped) and size themselves
   to fit two rows into whatever space the screen has
   ========================================================= */
.render-grid {
  display: flex; flex-wrap: wrap; justify-content: center; align-content: center; gap: 14px;
  container-type: size;
}
.render-grid { gap: 12px; margin-top: 18px; }
.render, .render:nth-child(1), .render:nth-child(2) {
  flex: 0 0 auto; grid-column: auto;
  width: var(--tile-w, 30%);          /* set by layoutRenders(): the largest size that fits them all */
  aspect-ratio: 4 / 3;
}
/* compact heading so the previews get the screen */
.renders { padding-top: 80px; padding-bottom: 68px; }
.renders .sec-head { max-width: none; display: flex; align-items: baseline; gap: 8px 20px; flex-wrap: wrap; }
.renders .sec-head .kicker { flex-basis: 100%; }
.renders .sec-head h2 { font-size: clamp(30px, 3vw, 44px); }
.renders .sub { margin: 0; font-size: 14px; }
@media (max-width: 760px), (max-height: 560px) {
  .renders { height: auto; }
  .render-grid { container-type: normal; flex: none; }
  .render, .render:nth-child(1), .render:nth-child(2) { width: min(100%, 560px); }
}

/* =========================================================
   v3: skills icons (real app icons)
   ========================================================= */
.tools { grid-template-columns: repeat(4, var(--tool)); gap: calc(var(--tool) * .2); --tool: clamp(44px, 3.9vw, 60px); }
.tools > img, .tools > .tile { width: var(--tool); height: var(--tool); display: block; transition: transform .3s var(--ease); }
.tools > img { object-fit: contain; }
.tools > .tile { border-radius: 22%; background: #1f2230; display: grid; place-items: center; padding: 16%; box-shadow: inset 0 -3px 0 rgba(0,0,0,.25); }
.tools > .tile img { width: 100%; height: 100%; object-fit: contain; }
.tools > .tile.capcut { background: #000; padding: 22%; overflow: hidden; }
.tools > .tile.capcut img { filter: invert(1); }          /* white CapCut mark on a black tile */
.tools > :hover { transform: translateY(-4px) rotate(-4deg); }

/* =========================================================
   v4: Character Hall loading screen + smoother hall <-> scene UI hand-off
   ========================================================= */
.hall-loader {
  position: absolute; inset: 0; z-index: 8; display: grid; place-items: center;
  background: radial-gradient(70% 60% at 50% 60%, #15161f 0%, var(--d3-bg) 70%);
  transition: opacity .9s var(--ease), visibility 0s .9s;
}
.hall-loader.done { opacity: 0; visibility: hidden; pointer-events: none; }
.hl-box { display: grid; gap: 14px; width: min(320px, 78vw); }
.hl-title { font: 800 24px/1 "Syne", var(--font); color: var(--d3-ink); letter-spacing: .01em; }
.hl-bar { height: 2px; background: rgba(255, 255, 255, .1); overflow: hidden; border-radius: 2px; }
.hl-bar i { display: block; height: 100%; width: 0; background: var(--d3-accent); transition: width .3s var(--ease); }
.hl-sub { font: 500 11px/1 "IBM Plex Mono", ui-monospace, monospace; letter-spacing: .14em; text-transform: uppercase; color: var(--d3-muted); }
.hl-sub b { color: var(--d3-ink); font-weight: 500; margin-left: 6px; }

/* the hall's own UI leaves quickly; the scene's panel arrives once the camera is nearly there */
.hall .sec-head, .hall .next-cue { transition: opacity .45s var(--ease), transform .6s var(--ease); }
.hall.isolated .sec-head { opacity: 0; transform: translateY(-10px); }
.hall-label { transition: opacity .35s var(--ease), background .25s; }
.iso-top, .iso-panel { transition: opacity .35s var(--ease), transform .35s var(--ease); transition-delay: 0s; }
/* shown by hall.js (class iso-ready) once the camera move is mostly done */
.hall.isolated:not(.iso-ready) .iso-top, .hall.isolated:not(.iso-ready) .iso-panel { opacity: 0; transform: translateY(12px); pointer-events: none; }
.hall.iso-ready .iso-top, .hall.iso-ready .iso-panel { transition: opacity .7s var(--ease), transform .9s var(--ease); }
.hall.iso-ready .iso-panel { transition-delay: .12s; }
.iso-who { transition: opacity .45s var(--ease), transform .6s var(--ease); }
.iso-ui.swapping .iso-who { opacity: 0; transform: translateY(10px); }

/* =========================================================
   v5: GodotCraft: Minecraft wallpaper backdrop under the section's original gradient,
   live map preview behind the Play button, hint while the mouse isn't captured
   ========================================================= */
.craft {
  background:
    linear-gradient(180deg, rgba(7, 9, 8, 0) 0%, rgba(7, 9, 8, .2) 45%, rgba(5, 6, 6, .9) 100%),   /* light at the top, dim towards the bottom */
    radial-gradient(80% 70% at 20% 100%, rgba(26, 36, 25, .78) 0%, rgba(11, 12, 17, .55) 65%),
    var(--d3-bg);
}
@media (orientation: portrait) {
  .craft {
    background:
      linear-gradient(180deg, rgba(7, 9, 8, 0) 0%, rgba(7, 9, 8, .2) 45%, rgba(5, 6, 6, .9) 100%),
      radial-gradient(80% 70% at 20% 100%, rgba(26, 36, 25, .78) 0%, rgba(11, 12, 17, .55) 65%),
      var(--d3-bg);
  }
}
/* the wallpaper only loads once the 3D side is warmed up (see warmWorld in main.js) */
.warm .craft { background-image:
    linear-gradient(180deg, rgba(7, 9, 8, 0) 0%, rgba(7, 9, 8, .2) 45%, rgba(5, 6, 6, .9) 100%),
    radial-gradient(80% 70% at 20% 100%, rgba(26, 36, 25, .78) 0%, rgba(11, 12, 17, .55) 65%),
    url("../assets/bg/godotcraft-wide.jpg"); background-size: auto, auto, cover; background-position: center; background-repeat: no-repeat; }
@media (orientation: portrait) {
  .warm .craft { background-image:
      linear-gradient(180deg, rgba(7, 9, 8, 0) 0%, rgba(7, 9, 8, .2) 45%, rgba(5, 6, 6, .9) 100%),
      radial-gradient(80% 70% at 20% 100%, rgba(26, 36, 25, .78) 0%, rgba(11, 12, 17, .55) 65%),
      url("../assets/bg/godotcraft-tall.jpg"); }
}
.craft .game-frame { background: #10160f; }
.game-preview { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.game-preview.pixel { image-rendering: pixelated; }
.game-frame .play { z-index: 1; background: linear-gradient(rgba(6, 10, 6, .15), rgba(6, 10, 6, .55)); }
.mouse-hint {
  position: absolute; z-index: 3; left: 50%; bottom: 14px; transform: translateX(-50%);
  margin: 0; padding: 8px 14px; border-radius: 999px; white-space: nowrap;
  background: rgba(0, 0, 0, .6); color: #fff; font-size: 12px; pointer-events: none;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
.mouse-hint kbd { height: 20px; min-width: 20px; font-size: 11px; }

/* =========================================================
   v4: About page spacing (less cluttered)
   ========================================================= */
.intro-grid { column-gap: clamp(40px, 5vw, 96px); }
.hello { justify-content: flex-start; gap: clamp(20px, 3vw, 48px); }
.mascot { width: clamp(72px, 6.5vw, 104px); margin-right: 0; }
.tools { --tool: clamp(46px, 3.6vw, 56px); grid-template-columns: repeat(3, var(--tool)); gap: 16px; margin-bottom: 8px; }
.intro-side .side-skills h3:first-child { margin-top: 8px; }
.intro-side .side-exp h3:first-child { margin-top: clamp(44px, 6vh, 64px); }
@media (max-width: 1100px) { .intro-side .side-exp h3:first-child, .intro-side .side-skills h3:first-child { margin-top: 0; } }
@media (max-width: 640px) { .intro-side .side-exp h3:first-child, .intro-side .side-skills h3:first-child { margin-top: 32px; } }
.intro .lead { margin-top: 32px; }

/* =========================================================
   v5: About page: everything a size up to use the space (the page still scales to fit the window)
   ========================================================= */
/* Desktop: the page is laid out once on a fixed 1240px "artboard" with fixed sizes, then fitIntro()
   scales the whole artboard uniformly to fill the window (bigger on big screens, smaller on small ones),
   so the proportions never change and nothing can collide. */
@media (min-width: 1101px) {
  .intro-grid {
    width: 1180px; max-width: none; flex: none; margin: 0;
    grid-template-columns: 330px minmax(0, 1fr) 270px;
    grid-template-areas: "photo main side" "photo contacts contacts";
    column-gap: 56px; row-gap: 36px;
  }
  .photo { aspect-ratio: auto; height: 500px; align-self: center; border-radius: 40px; }
  .hello { justify-content: space-between; gap: 16px; }
  .hello h2 { font-size: 100px; }
  .mascot { width: 92px; margin-right: 8px; }
  .intro .lead { font-size: 18px; line-height: 1.62; margin-top: 26px; max-width: none; }
  .intro h3 { font-size: 32px; margin: 40px 0 14px; }
  .intro p { font-size: 16.5px; }
  .intro p.strong { margin-top: 14px; }
  .intro-side .side-skills h3:first-child { margin-top: 14px; }
  .intro-side .side-exp h3:first-child { margin-top: 44px; }
  .tools { --tool: 62px; gap: 16px; }
  .contacts { font-size: 15px; gap: 12px 34px; flex-wrap: nowrap; white-space: nowrap; margin-top: 0; }
  .contacts svg { width: 26px; height: 26px; padding: 5px; }
  .side-btn { height: 48px; padding: 0 20px; font-size: 15px; }
}
@media (min-width: 1101px) and (max-width: 1250px) {
  .intro { padding-bottom: 92px; }
  .side-btn { position: fixed; top: auto; bottom: 22px; }
  .side-btn.spawn, .intro.show .side-btn.spawn { transform: none; }
}

/* =========================================================
   v3: sticker names sit in a pill below the sticker, above every other sticker
   ========================================================= */
.sticker:hover, .sticker:focus-visible { z-index: 20; }
.sticker .name {
  bottom: auto; top: calc(100% + 4px);
  padding: 4px 12px; border-radius: 999px;
  background: #fff; box-shadow: 0 6px 16px -6px rgba(70, 45, 20, .35), inset 0 0 0 1px rgba(43, 36, 51, .08);
  pointer-events: none;
}

/* =========================================================
   v4: start page music button
   ========================================================= */
.sound-btn {
  position: absolute; z-index: 9; right: clamp(16px, 3vw, 36px); bottom: clamp(18px, 4vh, 36px);
  display: flex; align-items: center; gap: 10px; padding: 10px 16px 10px 14px; border-radius: 999px;
  border: 1px solid rgba(255,255,255,.28); background: rgba(20,10,8,.32); color: #fff;
  font: 600 13px/1 "Outfit", sans-serif; letter-spacing: .04em;
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  transition: background .25s, opacity .3s;
}
.sound-btn:hover { background: rgba(20,10,8,.5); }
.sound-btn .eq { display: flex; align-items: flex-end; gap: 2px; height: 14px; }
.sound-btn .eq i { width: 3px; height: 4px; border-radius: 2px; background: currentColor; opacity: .8; }
.sound-btn.on .eq i { animation: eq 1s ease-in-out infinite; }
.sound-btn.on .eq i:nth-child(2) { animation-delay: -.3s; }
.sound-btn.on .eq i:nth-child(3) { animation-delay: -.6s; }
.sound-btn.on .eq i:nth-child(4) { animation-delay: -.15s; }
@keyframes eq { 0%, 100% { height: 4px; } 50% { height: 14px; } }

/* =========================================================
   v4: phones and tablets
   ========================================================= */
.touch-note { display: none; }
/* touch screens: the games need a keyboard, so show the preview with a note instead of a Play button */
@media (hover: none) and (pointer: coarse) {
  .keys { display: none; }
  .touch-note {
    display: block; margin: 20px 0 0; padding: 12px 14px; border-radius: 14px; font-size: 14px; line-height: 1.5;
    background: rgba(255,255,255,.08); box-shadow: inset 0 0 0 1px rgba(255,255,255,.12);
  }
  .w2d .touch-note { background: rgba(255,255,255,.7); box-shadow: inset 0 0 0 1px rgba(43,36,51,.1); }
  .game-frame .play, .game-frame .fs { display: none; }
  /* natural scrolling: snapping fights the finger on long sections */
  .world { scroll-snap-type: none; }
  .render:hover video, .render:hover img { transform: none; }
}

@media (max-width: 760px) {
  /* renders: two across so all six fit on one screen */
  .render-grid { gap: 10px; align-content: start; }
  .render, .render:nth-child(1), .render:nth-child(2) { width: calc(50% - 5px); aspect-ratio: 4 / 3; border-radius: 14px; }
  .render-cap { left: 10px; right: 10px; bottom: 8px; }
  .render-cap b { font-size: 13px; line-height: 1.2; }
  .render-cap small, .render-cap .open { display: none; }
  .renders .sec-head h2 { font-size: 34px; }
  .lightbox { padding: 64px 12px 24px; }
  .lb-media video { border-radius: 10px; }
  /* games: preview first, full width */
  .game { justify-content: flex-start; }
  .game-layout { gap: 20px; flex: none; }
  .game-frame { border-radius: 16px; }
  /* sound button sits clear of the scroll cue */
  .sound-btn { padding: 9px 13px 9px 12px; font-size: 12px; }
}

/* tablets in portrait (e.g. 800 x 1280): stack the games, keep things big */
@media (min-width: 761px) and (max-width: 1100px) and (orientation: portrait) {
  .game-layout { grid-template-columns: 1fr; }
  .game { justify-content: center; }
}

/* =========================================================
   v6: start page = portal into the title. The About page is a normal page after it.
   ========================================================= */
.hero-wrap { height: 300vh; }
/* lvh: the pinned scene also covers the space the phone's address bar gives back while scrolling */
.hero-sticky { height: 100vh; height: 100lvh; }
.sh-bloom { display: none; }
.sh-glow {
  /* the glow is drawn once; scrolling only changes its opacity and zoom (cheap), never the blur itself */
  text-shadow: 0 0 14px rgba(255,246,228,.95), 0 0 48px rgba(255,214,160,.85), 0 0 130px rgba(255,184,110,.7);
  will-change: opacity, transform;
}
.sh-bg { transform-origin: 50% var(--ty, 50%); will-change: transform; }
.sh-fg { transform-origin: 50% 100%; will-change: transform, opacity; }
/* warm light pouring out of the text: a wash far bigger than the screen, so there is no visible circle */
.sh-light {
  position: absolute; z-index: 6; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(160% 130% at 50% var(--ty, 50%), #fffaf0 0%, #ffeccd 38%, #ffd9a6 75%, #f6c690 100%);
}
.scroll-cue { z-index: 8; }

.intro {
  position: relative; inset: auto; z-index: auto;
  height: auto; min-height: 100vh; min-height: 100svh;
  visibility: visible; pointer-events: auto; overflow: visible;
  background: var(--paper);
}
.intro.show::after { display: none; }
/* wide, tall-enough screens: the About page is exactly one screen (fitIntro scales the artboard into it) */
@media (min-width: 1101px) and (min-height: 640px) {
  .intro { height: 100vh; height: 100svh; overflow: hidden; }
}
@media (min-width: 1101px) and (max-width: 1250px) and (min-height: 640px) {
  .side-btn { position: absolute; bottom: 22px; }
}
/* everywhere else: a normal scrolling page, the 3D / 2D buttons sit side by side at the end */
@media (max-width: 1100px), (max-height: 639px) {
  .intro { display: grid; grid-template-columns: 1fr 1fr; column-gap: 12px; align-content: start; padding-bottom: 40px; }
  .intro-grid { grid-column: 1 / -1; order: 1; }
  .side-btn, .side-btn.spawn, .intro.show .side-btn.spawn {
    position: static; order: 2; justify-content: center; height: 54px; margin-top: 40px; font-size: 16px; transform: none;
  }
}

/* =========================================================
   v6: nav: About button on phones too, music button at the right end
   ========================================================= */
@media (max-width: 760px) { body.view-home .pills[data-for="home"] { display: flex; } }
.snd { display: grid; place-items: center; padding: 0; }
.snd svg { width: 18px; height: 18px; fill: currentColor; }
.snd .snd-off, .snd.muted .snd-on { display: none; }
.snd.muted .snd-off { display: block; }
.snd.muted { opacity: .6; }
@media (max-width: 480px) {
  .snd svg { width: 16px; height: 16px; }
  .pills[data-for="home"] button { padding: 8px 10px; }
}

/* =========================================================
   v6: Character Hall: nothing of the hall shows until it has loaded, then a guide teaches the controls
   ========================================================= */
.hall .sec-head, .hall .next-cue, .hall .hall-labels, .hall .coach { transition: opacity .6s var(--ease); }
.hall:not(.ready) .sec-head, .hall:not(.ready) .next-cue, .hall:not(.ready) .hall-labels, .hall:not(.ready) .coach { opacity: 0; pointer-events: none; }
.hall-loader { background: var(--d3-bg); }

.coach {
  position: absolute; z-index: 5; left: 50%; bottom: clamp(96px, 16vh, 150px); transform: translateX(-50%);
  pointer-events: none; width: max-content; max-width: calc(100vw - 32px);
}
.coach-step {
  display: none; align-items: center; gap: 14px;
  padding: 12px 20px 12px 14px; border-radius: 999px;
  background: rgba(12, 12, 18, .78); color: #fff; font-size: 15px;
  box-shadow: 0 10px 40px -10px rgba(0,0,0,.6), inset 0 0 0 1px rgba(255,255,255,.14);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  animation: coachIn .6s var(--ease) both;
}
.coach-step b { font-weight: 600; }
.coach[data-step="drag"] [data-step="drag"], .coach[data-step="tap"] [data-step="tap"] { display: flex; }
.coach[data-step="done"] { opacity: 0 !important; }
@keyframes coachIn { from { opacity: 0; transform: translateY(10px) scale(.96); } }

/* gesture icons: a fingertip that swipes side to side, or taps with a ripple */
.coach-gesture { position: relative; flex: none; width: 44px; height: 30px; }
.coach-gesture i {
  position: absolute; top: 50%; left: 50%; width: 16px; height: 16px; margin: -8px 0 0 -8px; border-radius: 50%;
  background: #fff; box-shadow: 0 0 0 4px rgba(255,255,255,.25);
}
.coach-gesture.drag::before {
  content: ""; position: absolute; top: 50%; left: 4px; right: 4px; height: 2px; margin-top: -1px; border-radius: 2px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.5), transparent);
}
.coach-gesture.drag i { animation: swipe 1.8s ease-in-out infinite; }
@keyframes swipe { 0%, 100% { transform: translateX(-14px); } 50% { transform: translateX(14px); } }
.coach-gesture.tap i { animation: tapDot 1.6s ease-in-out infinite; }
.coach-gesture.tap::after {
  content: ""; position: absolute; top: 50%; left: 50%; width: 16px; height: 16px; margin: -8px 0 0 -8px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,.8); animation: ripple 1.6s ease-out infinite;
}
@keyframes tapDot { 0%, 100% { transform: scale(1); } 20% { transform: scale(.75); } 40% { transform: scale(1); } }
@keyframes ripple { 0%, 15% { transform: scale(.6); opacity: 0; } 25% { opacity: 1; } 100% { transform: scale(2.4); opacity: 0; } }

/* while the guide asks for a tap, the character name tags pulse so it's obvious what to tap */
.hall.coach-tap .hall-label { animation: labelPulse 1.6s ease-in-out infinite; }
@keyframes labelPulse {
  0%, 100% { box-shadow: inset 0 0 0 1px rgba(255,255,255,.14), 0 0 0 0 rgba(242,193,78,.55); }
  50% { box-shadow: inset 0 0 0 1px rgba(255,255,255,.3), 0 0 0 10px rgba(242,193,78,0); }
}

/* =========================================================
   v6: 2D guides: characters invite a tap until you've opened one; stickers take turns wiggling
   ========================================================= */
.coach-pill {
  position: relative; z-index: 3; align-self: center; margin: 4px auto 0;
  display: flex; align-items: center; gap: 12px; width: max-content; max-width: 100%;
  padding: 10px 18px 10px 12px; border-radius: 999px; font-size: 14px; font-weight: 600;
  background: #2b2433; color: #fff; box-shadow: 0 12px 30px -12px rgba(43,36,51,.6);
  animation: coachIn .6s var(--ease) 1s both;
  transition: opacity .4s, transform .4s;
}
.coach-pill .coach-gesture { width: 30px; height: 26px; }
.coach-pill.gone { opacity: 0; transform: translateY(8px); pointer-events: none; }
.featured.invite .hero-char .blob { animation: blobPulse 2.4s ease-in-out infinite; }
.featured.invite .hero-char:nth-child(2) .blob { animation-delay: .8s; }
.featured.invite .hero-char:nth-child(3) .blob { animation-delay: 1.6s; }
@keyframes blobPulse { 0%, 100% { transform: translateX(-50%) scale(.92); opacity: .12; } 50% { transform: translateX(-50%) scale(1.05); opacity: .3; } }
.featured.invite .hero-char .tag em { opacity: 1; }
.stickers.invite .sticker.nudge { animation: wiggle .9s ease-in-out; }
@keyframes wiggle {
  0%, 100% { transform: rotate(calc(var(--r) * 1deg)); }
  20% { transform: rotate(calc(var(--r) * 1deg + 8deg)) scale(1.06); }
  45% { transform: rotate(calc(var(--r) * 1deg - 6deg)) scale(1.06); }
  70% { transform: rotate(calc(var(--r) * 1deg + 3deg)); }
}
@media (max-width: 760px) {
  .coach { bottom: 110px; }
  .coach-step { font-size: 14px; padding: 10px 16px 10px 12px; }
  .coach-pill { font-size: 13px; margin-top: 16px; }
}
