/* ═══════════════════════════════════════════════════════════════════
   Bhavesh Waghmare - portfolio
   An engineer's sketchbook: graph paper, hand-drawn marks, hot pink.
   Palette derived from zuup.dev. Single accent, locked page-wide.
   ═══════════════════════════════════════════════════════════════════ */

:root {
  /* surfaces */
  --ink:      #070a10;
  --ink-2:    #0b111c;
  --panel:    #0f1420;
  --line:     #232a3d;
  --line-2:   #38445f;

  /* type */
  --chalk:    #f2f4f8;
  --mute:     #a5adbf;
  --faint:    #7c859c;

  /* the one accent */
  --hot:      #ff3d78;
  --hot-ink:  #070a10;
  --hot-wash: rgba(255, 61, 120, .12);
  --hot-line: rgba(255, 61, 120, .38);
  --hot-deep: #96163e;                        /* the underside of a pressed key */
  --hot-glow: rgba(255, 61, 120, .28);

  /* shape system
     doodle panels get an irregular radius, chips are pills,
     small tiles are 14px. No other radii on this page. */
  --r-doodle:   18px 34px 20px 30px / 30px 18px 32px 20px;
  --r-doodle-b: 32px 18px 30px 22px / 20px 32px 18px 34px;
  --r-tile:     14px;
  --r-pill:     999px;

  --font:  "Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;
  --hand:  "Kalam", "Bricolage Grotesque", cursive;
  --mono:  "JetBrains Mono", ui-monospace, monospace;

  --shell: 1180px;
  --sec-y: clamp(4.5rem, 9vw, 8rem);

  --ease: cubic-bezier(.16, 1, .3, 1);

  /* z scale */
  --z-nav: 100;
  --z-menu: 90;
}

/* ── reset ───────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 90px;
  -webkit-text-size-adjust: 100%;
}

body {
  min-height: 100dvh;
  background: var(--ink);
  color: var(--chalk);
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.65;
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* graph paper, the whole reason this reads as a sketchbook */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(120, 140, 190, .055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(120, 140, 190, .055) 1px, transparent 1px),
    linear-gradient(rgba(120, 140, 190, .028) 1px, transparent 1px),
    linear-gradient(90deg, rgba(120, 140, 190, .028) 1px, transparent 1px);
  background-size: 120px 120px, 120px 120px, 24px 24px, 24px 24px;
}

/* a soft pink bloom behind the top of the page */
body::after {
  content: "";
  position: fixed;
  top: -30vh;
  left: 50%;
  width: 90vw;
  max-width: 900px;
  aspect-ratio: 1;
  transform: translateX(-50%);
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(circle, rgba(255, 61, 120, .10), transparent 62%);
}

img, svg { display: block; max-width: 100%; }

/* The hidden attribute is only `display:none` from the UA sheet, so any
   author display rule silently beats it. Make it win. */
[hidden] { display: none !important; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; padding: 0; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

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

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.skip-link {
  position: absolute;
  top: -100px;
  left: 1rem;
  z-index: 200;
  padding: .7rem 1.1rem;
  background: var(--hot);
  color: var(--hot-ink);
  font-weight: 700;
  border-radius: var(--r-tile);
  transition: top .2s var(--ease);
}
.skip-link:focus { top: 1rem; }

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: clamp(1.1rem, 4vw, 2.5rem);
}

/* ── icons (drawn by hand, per the sketchbook brief) ─────────────── */
.ico, .panel-ico, .feat-ico, .idx-ico, .win-ico {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  overflow: visible;
}
.ico { width: 1.15em; height: 1.15em; flex: none; }
/* Solid marks like the GitHub octocat. Relying on the path's own fill
   attribute was not enough: the inherited fill:none above still won, so
   only fragments of the logo drew. Set it on the svg and it inherits.
   Slightly larger than the stroked icons too, because at 1.15em the
   octocat's tentacle falls below a pixel and only its head reads. */
.ico-solid { fill: currentColor; stroke: none; width: 1.4em; height: 1.4em; }
.panel-ico, .feat-ico { width: 2.6rem; height: 2.6rem; stroke-width: 1.7; }
.idx-ico { width: 2rem; height: 2rem; stroke-width: 1.8; color: var(--hot); }
.win-ico { width: 2.4rem; height: 2.4rem; stroke-width: 1.7; color: var(--hot); }

/* ── typography ──────────────────────────────────────────────────── */
.h2 {
  font-size: clamp(2rem, 4.4vw, 3.15rem);
  line-height: 1.08;
  font-weight: 700;
  letter-spacing: -.025em;
  text-wrap: balance;
}

.eyebrow {
  display: inline-block;
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--hot);
  margin-bottom: .9rem;
}

.scribble {
  font-family: var(--hand);
  font-weight: 700;
  color: var(--hot);
  line-height: 1.3;
}

/* A squiggle under a heading, the way you underline something twice in a
   notebook when it matters. Reserved for the handwritten headings and the
   featured project titles so it stays an emphasis, not a texture. */
.squiggle {
  text-decoration: underline wavy var(--hot);
  text-decoration-thickness: 2px;
  text-underline-offset: 9px;
  text-decoration-skip-ink: none;
}

.sec-head { max-width: 44rem; margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.sec-sub {
  margin-top: 1rem;
  color: var(--mute);
  font-size: 1.05rem;
  max-width: 46ch;
}

.sec { padding-block: var(--sec-y); position: relative; }

/* The mascot turns up again as a huge faint outline running off the edge of
   a section, like a doodle in the margin that ran out of page. Decorative
   only, and clipped by the section it belongs to. */
.sec:has(.watermark) { overflow: hidden; }
.watermark {
  position: absolute;
  top: 50%;
  width: clamp(300px, 34vw, 520px);
  aspect-ratio: 420 / 470;
  fill: none;
  stroke: var(--chalk);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .07;
  pointer-events: none;
  z-index: 0;
}
.watermark-left  { left: -14%; transform: translateY(-50%) rotate(-8deg); }
.watermark-right { right: -14%; transform: translateY(-50%) rotate(7deg); }
/* keep the real content above the doodle */
.sec > .shell { position: relative; z-index: 1; }

@media (max-width: 860px) { .watermark { display: none; } }
.sec-tint { background: linear-gradient(180deg, transparent, var(--ink-2) 12% 88%, transparent); }

/* ── buttons ─────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  min-height: 48px;
  padding: .85rem 1.5rem;
  border-radius: var(--r-pill);
  font-weight: 600;
  font-size: 1rem;
  white-space: nowrap;
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform .18s var(--ease), background-color .18s var(--ease),
              border-color .18s var(--ease), color .18s var(--ease),
              box-shadow .18s var(--ease);
}

/* Buttons sit on a solid underside and physically collapse when pressed,
   so a click feels like pushing a key rather than tinting a rectangle. */
.btn-primary {
  background: var(--hot);
  color: var(--hot-ink);
  box-shadow: 0 6px 0 0 var(--hot-deep), 0 0 34px var(--hot-glow);
}
.btn-primary:hover {
  background: #ff5c8d;
  transform: translateY(-2px);
  box-shadow: 0 9px 0 0 var(--hot-deep), 0 0 44px var(--hot-glow);
}
.btn-primary:active {
  transform: translateY(5px);
  box-shadow: 0 0 0 0 var(--hot-deep), 0 0 22px var(--hot-glow);
}

/* Secondary actions are drawn rather than built: a dashed outline, flat on
   the page. Solid and raised means "do this", dashed and flat means "or
   have a look at this". Same rule governs the project cards below. */
.btn-ghost {
  border: 2px dashed var(--line-2);
  color: var(--chalk);
}
.btn-ghost:hover { border-color: var(--hot); color: var(--hot); transform: translateY(-2px); }
.btn-ghost:active { transform: translateY(0) scale(.98); }

.btn-sm { min-height: 40px; padding: .5rem 1.05rem; font-size: .92rem; }

/* ── nav ─────────────────────────────────────────────────────────── */
/* The nav is a floating capsule rather than a bar, so the page reads as
   something laid on the desk with the controls resting on top of it. */
.nav {
  position: fixed;
  top: clamp(.6rem, 1.6vw, 1.1rem);
  left: 0;
  right: 0;
  z-index: var(--z-nav);
  display: flex;
  justify-content: center;
  padding-inline: clamp(.75rem, 3vw, 1.5rem);
  pointer-events: none;
}

.nav-pill {
  position: relative;
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: clamp(.4rem, 1.2vw, 1rem);
  max-width: 100%;
  height: 60px;
  padding: 0 .4rem 0 1rem;
  background: rgba(11, 15, 25, .82);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  transition: background-color .25s var(--ease), border-color .25s var(--ease),
              box-shadow .25s var(--ease);
}
.nav.stuck .nav-pill {
  background: rgba(11, 15, 25, .95);
  border-color: var(--line-2);
  box-shadow: 0 14px 40px rgba(0, 0, 0, .55);
}

.brand { display: flex; align-items: center; gap: .5rem; min-height: 44px; flex: none; }
.brand-mark { width: 30px; height: 30px; color: var(--hot); flex: none; }
.brand-mark svg { fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; overflow: visible; }
.brand-word { font-weight: 700; font-size: 1.1rem; letter-spacing: -.02em; }
.brand-dot { color: var(--hot); }

.nav-links {
  display: flex;
  align-items: center;
  gap: .15rem;
  padding-left: .5rem;
  margin-left: .35rem;
  border-left: 1px solid var(--line);
}
.nav-links a {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 44px;
  padding-inline: .8rem;
  border-radius: var(--r-pill);
  font-size: .92rem;
  white-space: nowrap;
  color: var(--mute);
  transition: color .18s var(--ease), background-color .18s var(--ease);
}
.nav-links a:hover { color: var(--chalk); background: rgba(255, 255, 255, .06); }
/* the section you are in sits in its own chip, the way a tab does */
.nav-links a.active { color: var(--chalk); background: rgba(255, 255, 255, .1); }

.burger { display: none; width: 44px; height: 44px; flex-direction: column; justify-content: center; gap: 5px; align-items: center; }
.burger span { width: 22px; height: 2px; background: var(--chalk); border-radius: 2px; transition: transform .24s var(--ease), opacity .18s var(--ease); }
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ── hero ────────────────────────────────────────────────────────── */
/* the capsule floats over the page, so the hero reserves its own top space */
.hero { padding-top: clamp(6.5rem, 11vw, 9rem); padding-bottom: clamp(3rem, 7vw, 5.5rem); }

.hero-grid {
  display: grid;
  grid-template-columns: 1.38fr .62fr;
  align-items: center;
  gap: clamp(2rem, 4vw, 3rem);
}

.hero-hi {
  position: relative;
  display: inline-block;
  font-size: 1.4rem;
  transform: rotate(-2.5deg);
  margin-bottom: 1.1rem;
}
.scribble-arrow {
  position: absolute;
  right: -78px;
  top: 8px;
  width: 72px;
  fill: none;
  stroke: var(--hot);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  overflow: visible;
}

/* sized so the headline holds to 2 lines at desktop, with the break
   placed by hand rather than left to the wrap */
.hero-title {
  font-size: clamp(2.15rem, 4.4vw, 3.5rem);
  line-height: 1.06;
  font-weight: 800;
  letter-spacing: -.035em;
}
.hero-title br { display: none; }
@media (min-width: 861px) { .hero-title br { display: block; } }
.mark { position: relative; display: inline-block; color: var(--hot); padding-bottom: .12em; }
.mark-line {
  position: absolute;
  left: -1%;
  bottom: -.02em;
  width: 102%;
  height: .3em;
  fill: none;
  stroke: var(--hot);
  stroke-width: 5;
  stroke-linecap: round;
  opacity: .55;
  overflow: visible;
}

.hero-sub {
  margin-top: 1.5rem;
  max-width: 40ch;
  color: var(--mute);
  font-size: clamp(1.02rem, 1.6vw, 1.15rem);
}

.hero-cta { display: flex; flex-wrap: wrap; gap: .9rem; margin-top: 2.2rem; }

/* mascot */
.hero-bot { position: relative; justify-self: center; width: 100%; max-width: 380px; }
.bot {
  width: 100%;
  height: auto;
  fill: none;
  stroke: var(--chalk);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
  overflow: visible;
}
/* No bob: it used to hover because it had no legs. Now that it has feet,
   floating just looks like a bug. Its life comes from the face instead. */
.bot-ground { fill: none; stroke: var(--chalk); stroke-width: 4; opacity: .2; }
.bot-head, .bot-body { fill: var(--panel); }
.bot-eyes-fallback { fill: var(--hot); stroke: none; }
.bot-chip { fill: var(--hot-wash); stroke: var(--hot); }
.bot-bulb { fill: var(--hot); stroke: var(--hot); animation: blink 2.6s ease-in-out infinite; }
.bot-wire, .bot-part { stroke: var(--chalk); }
.bot-trace { stroke: var(--hot); stroke-width: 3; }

/* ═══════════════════════════════════════════════════════════════════
   THE ROBOT IN 3D
   Six-sided boxes on preserve-3d. Every face is a real plane, so it
   genuinely turns rather than faking depth with a drawing, and it costs
   nothing but CSS. Everything scales from the single unit --u.
   ═══════════════════════════════════════════════════════════════════ */
.bot3d {
  --u: clamp(1px, .52vw, 1.62px);
  --headW: calc(var(--u) * 116);
  --headH: calc(var(--u) * 88);
  --headD: calc(var(--u) * 82);
  --bodyW: calc(var(--u) * 96);
  --bodyH: calc(var(--u) * 78);
  --bodyD: calc(var(--u) * 70);
  --edge: rgba(242, 244, 248, .85);

  position: relative;
  width: 100%;
  height: calc(var(--u) * 250);
  display: grid;
  place-items: start center;
  perspective: calc(var(--u) * 900);
}

/* script.js writes --ry and --rx as the pointer moves */
.b3-rig {
  position: relative;
  width: var(--headW);
  transform-style: preserve-3d;
  transform: rotateX(var(--rx, -6deg)) rotateY(var(--ry, -22deg));
  transition: transform .5s cubic-bezier(.22, 1, .36, 1);
}

.b3-box { position: relative; transform-style: preserve-3d; }
.b3-f {
  position: absolute;
  inset: 0;
  background: var(--panel);
  border: 2px solid var(--edge);
  border-radius: 6px;
}

/* ── head ───────────────────────────────────────────────────────── */
.b3-head { width: var(--headW); height: var(--headH); margin-inline: auto; }
.b3-head > .b3-front  { transform: translateZ(calc(var(--headD) / 2)); }
.b3-head > .b3-back   { transform: rotateY(180deg) translateZ(calc(var(--headD) / 2)); }
.b3-head > .b3-left,
.b3-head > .b3-right  { width: var(--headD); left: calc((var(--headW) - var(--headD)) / 2); }
.b3-head > .b3-left   { transform: rotateY(-90deg) translateZ(calc(var(--headW) / 2)); }
.b3-head > .b3-right  { transform: rotateY(90deg) translateZ(calc(var(--headW) / 2)); }
.b3-head > .b3-top,
.b3-head > .b3-bottom { height: var(--headD); top: calc((var(--headH) - var(--headD)) / 2); }
.b3-head > .b3-top    { transform: rotateX(90deg) translateZ(calc(var(--headH) / 2)); }
.b3-head > .b3-bottom { transform: rotateX(-90deg) translateZ(calc(var(--headH) / 2)); }

/* the face panel, inset like a screen in its bezel */
.b3-screen {
  position: absolute;
  left: 12%;
  top: 16%;
  width: 76%;
  height: 68%;
  background: #05070c;
  border-radius: 4px;
}

/* ── body ───────────────────────────────────────────────────────── */
.b3-body {
  width: var(--bodyW);
  height: var(--bodyH);
  margin: calc(var(--u) * 16) auto 0;
}
.b3-body > .b3-front  { transform: translateZ(calc(var(--bodyD) / 2)); }
.b3-body > .b3-back   { transform: rotateY(180deg) translateZ(calc(var(--bodyD) / 2)); }
.b3-body > .b3-left,
.b3-body > .b3-right  { width: var(--bodyD); left: calc((var(--bodyW) - var(--bodyD)) / 2); }
.b3-body > .b3-left   { transform: rotateY(-90deg) translateZ(calc(var(--bodyW) / 2)); }
.b3-body > .b3-right  { transform: rotateY(90deg) translateZ(calc(var(--bodyW) / 2)); }
.b3-body > .b3-top,
.b3-body > .b3-bottom { height: var(--bodyD); top: calc((var(--bodyH) - var(--bodyD)) / 2); }
.b3-body > .b3-top    { transform: rotateX(90deg) translateZ(calc(var(--bodyH) / 2)); }
.b3-body > .b3-bottom { transform: rotateX(-90deg) translateZ(calc(var(--bodyH) / 2)); }

.b3-chip {
  position: absolute;
  left: 26%;
  top: 22%;
  width: 48%;
  height: 46%;
  background: var(--hot-wash);
  border: 2px solid var(--hot);
  border-radius: 3px;
}

/* ── antenna, ears, neck, limbs ─────────────────────────────────── */
.b3-antenna {
  position: absolute;
  left: 50%;
  bottom: 100%;
  width: 2px;
  height: calc(var(--u) * 26);
  background: var(--edge);
  transform: translateX(-50%);
}
.b3-bulb {
  position: absolute;
  left: 50%;
  top: calc(var(--u) * -10);
  width: calc(var(--u) * 13);
  height: calc(var(--u) * 13);
  margin-left: calc(var(--u) * -6.5);
  border-radius: 50%;
  background: var(--hot);
  box-shadow: 0 0 calc(var(--u) * 10) var(--hot);
  animation: blink 2.6s ease-in-out infinite;
}

.b3-ear {
  position: absolute;
  top: calc(var(--u) * 26);
  width: calc(var(--u) * 9);
  height: calc(var(--u) * 34);
  background: var(--panel);
  border: 2px solid var(--edge);
  border-radius: 3px;
}
.b3-ear-l { left: calc(var(--u) * -9); }
.b3-ear-r { right: calc(var(--u) * -9); }

.b3-neck {
  position: absolute;
  left: 50%;
  top: var(--headH);
  width: calc(var(--u) * 26);
  height: calc(var(--u) * 16);
  margin-left: calc(var(--u) * -13);
  border-left: 2px solid var(--edge);
  border-right: 2px solid var(--edge);
}

.b3-limb { position: absolute; background: var(--panel); border: 2px solid var(--edge); border-radius: 4px; }
/* the rig is head-width but the arms hang off the BODY, which is narrower,
   so they are inset by half the difference rather than sat at the edge */
.b3-arm-l, .b3-arm-r { width: calc(var(--u) * 8); height: calc(var(--u) * 46); top: calc(var(--u) * 114); }
.b3-arm-l { left: calc(var(--u) * 2); transform: rotate(6deg); }
.b3-arm-r { right: calc(var(--u) * 2); transform: rotate(-6deg); }
.b3-leg-l, .b3-leg-r { width: calc(var(--u) * 10); height: calc(var(--u) * 34); top: calc(var(--u) * 182); }
.b3-leg-l { left: calc(var(--u) * 30); }
.b3-leg-r { right: calc(var(--u) * 30); }

/* it stands on something, rather than hovering */
.b3-shadow {
  position: absolute;
  bottom: calc(var(--u) * 32);
  left: 50%;
  width: calc(var(--u) * 120);
  height: 3px;
  transform: translateX(-50%);
  border-radius: 2px;
  background: linear-gradient(90deg, transparent,
              rgba(242, 244, 248, .3) 18%, rgba(242, 244, 248, .3) 82%, transparent);
}

/* The robot's size comes from --u, not from its container, so it has to be
   stepped down explicitly on smaller screens or it bursts out of the slot. */
@media (max-width: 1024px) { .bot3d { --u: 1.28px; } }
@media (max-width: 720px)  { .bot3d { --u: 1.02px; } }

/* the flat drawing is only a fallback where preserve-3d is unsupported */
.bot-flat { display: none; }
@supports not (transform-style: preserve-3d) {
  .bot3d { display: none; }
  .bot-flat { display: block; }
}

.bot-say {
  position: absolute;
  top: 4%;
  left: -4%;
  font-size: 1.35rem;
  transform: rotate(-8deg);
}

.bot-spark {
  position: absolute;
  fill: none;
  stroke: var(--hot);
  stroke-width: 3;
  stroke-linecap: round;
  overflow: visible;
}
.spark-a { width: 30px; top: 16%; right: -2%; animation: twinkle 3.4s ease-in-out infinite; }
.spark-b { width: 22px; bottom: 16%; left: -3%; animation: twinkle 3.4s ease-in-out .9s infinite; }

@keyframes blink { 0%, 100% { opacity: 1 } 50% { opacity: .35 } }
@keyframes twinkle { 0%, 100% { opacity: .25; transform: scale(.85) } 50% { opacity: 1; transform: scale(1.1) } }

/* ── marquee ─────────────────────────────────────────────────────── */
.marquee {
  border-block: 1px solid var(--line);
  padding-block: 1rem;
  overflow: hidden;
  background: var(--ink-2);
}
.marquee-track {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  width: max-content;
  animation: slide 38s linear infinite;
}
.marquee-track span {
  font-family: var(--mono);
  font-size: .84rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--mute);
  white-space: nowrap;
}
.marquee-track b { width: 7px; height: 7px; border-radius: 50%; background: var(--hot); opacity: .65; flex: none; }
@keyframes slide { to { transform: translateX(-50%) } }

/* ── about ───────────────────────────────────────────────────────── */
.about-grid {
  display: grid;
  grid-template-columns: 1.1fr .9fr;
  gap: clamp(2rem, 6vw, 5rem);
  align-items: start;
}
.about-copy p { margin-top: 1.15rem; color: var(--mute); max-width: 54ch; }
.about-copy strong { color: var(--chalk); font-weight: 600; }
.about-copy .h2 { margin-bottom: .5rem; }

.notes {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.1rem;
  padding-top: .5rem;
}
.note {
  padding: 1.5rem 1.25rem;
  background: var(--panel);
  border: 2px solid var(--line);
  border-radius: var(--r-doodle);
  transition: transform .25s var(--ease), border-color .25s var(--ease);
}
.note-a { transform: rotate(-2.2deg); }
.note-b { transform: rotate(1.8deg); margin-top: 1.4rem; }
.note-c { transform: rotate(1.4deg); }
.note-d { transform: rotate(-1.6deg); margin-top: 1.4rem; border-radius: var(--r-doodle-b); }
.note:hover {
  transform: rotate(0) translateY(-4px);
  border-color: var(--hot-line);
  box-shadow: 0 0 40px rgba(255, 61, 120, .13);
}

.note-num {
  display: block;
  font-size: clamp(1.9rem, 4vw, 2.5rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.03em;
  color: var(--hot);
}
.note-cap {
  display: block;
  margin-top: .5rem;
  font-size: .85rem;
  color: var(--mute);
  line-height: 1.4;
}

/* ── what I build ────────────────────────────────────────────────── */
.panels {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(1.25rem, 3vw, 2rem);
}
.panel {
  position: relative;
  padding: 2rem 1.9rem;
  background: var(--panel);
  border: 2px solid var(--line);
  border-radius: var(--r-doodle);
  color: var(--chalk);
  transition: transform .28s var(--ease), border-color .28s var(--ease);
}
/* the second stroke: what makes a box look drawn twice */
.panel::before {
  content: "";
  position: absolute;
  inset: 5px;
  border: 2px solid var(--line);
  border-radius: var(--r-doodle-b);
  opacity: .38;
  pointer-events: none;
  transition: border-color .28s var(--ease);
}
.panel:nth-child(even) { border-radius: var(--r-doodle-b); }
.panel:nth-child(even)::before { border-radius: var(--r-doodle); }
.panel:nth-child(2), .panel:nth-child(3) { transform: translateY(1.75rem); }
.panel:hover { border-color: var(--hot-line); }
.panel:hover::before { border-color: var(--hot-line); }

.panel-ico { color: var(--hot); margin-bottom: 1.1rem; }
.panel h3 { font-size: 1.3rem; font-weight: 700; letter-spacing: -.02em; }
.panel p { margin-top: .7rem; color: var(--mute); font-size: .98rem; }

/* ── skills ──────────────────────────────────────────────────────── */
.clusters {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(1.75rem, 4vw, 3rem);
}
.cluster-name {
  font-family: var(--hand);
  font-size: 1.45rem;
  font-weight: 700;
  color: var(--chalk);
  margin-bottom: 1.1rem;
  text-decoration: underline wavy var(--hot);
  text-decoration-thickness: 2px;
  text-underline-offset: 7px;
  text-decoration-skip-ink: none;
}
.chips { display: flex; flex-wrap: wrap; gap: .65rem; align-items: center; }
.chip {
  padding: .5rem 1.05rem;
  border-radius: var(--r-pill);
  border: 2px solid var(--line-2);
  color: var(--mute);
  font-size: .88rem;
  line-height: 1.2;
  transition: transform .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
  cursor: default;
}
.chip:hover { transform: translateY(-3px) rotate(-1.5deg); border-color: var(--hot); color: var(--chalk); }
.chip.lv2 { font-size: 1rem; padding: .58rem 1.2rem; color: var(--chalk); }
.chip.lv3 {
  font-size: 1.1rem;
  font-weight: 600;
  padding: .68rem 1.4rem;
  color: var(--hot);
  border-color: var(--hot);
  background: var(--hot-wash);
}

.chip-key {
  margin-top: 2rem;
  font-size: 1.1rem;
  transform: rotate(-1.5deg);
  opacity: .85;
}

/* ── work: featured bento ────────────────────────────────────────── */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(1.25rem, 3vw, 1.75rem);
  margin-bottom: clamp(1.25rem, 3vw, 1.75rem);
}
.feat {
  display: flex;
  flex-direction: column;
  padding: 1.9rem;
  background: var(--panel);
  border: 2px solid var(--line);
  border-radius: var(--r-doodle);
  transition: transform .28s var(--ease), border-color .28s var(--ease);
}
/* The lead used to span two rows, which stretched it to the height of the
   two cards beside it and left a lot of dead space under its content. It
   now sits in a plain 2x2, and earns its emphasis from the wash of colour
   rather than from being oversized. */
.feat-lead {
  background:
    radial-gradient(120% 90% at 80% 0%, rgba(255, 61, 120, .13), transparent 60%),
    var(--panel);
  border-radius: var(--r-doodle-b);
}
/* the newest build runs the full width above the 2x2, so the grid still
   has no empty cell and the latest thing is the first thing read */
.feat-wide { grid-column: 1 / -1; }

.feat:hover { transform: translateY(-5px); border-color: var(--hot-line); }
.feat-lead:hover { box-shadow: 0 0 60px rgba(255, 61, 120, .16); }

.feat-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; margin-bottom: 1.2rem; }
.feat-ico { color: var(--hot); }

.tag {
  padding: .3rem .8rem;
  border-radius: var(--r-pill);
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
  border: 1px solid;
}
.tag-live { color: var(--hot); border-color: var(--hot-line); background: var(--hot-wash); }
.tag-done { color: var(--mute); border-color: var(--line-2); }
.tag-wip  { color: var(--mute); border-color: var(--line-2); border-style: dashed; }

/* unfinished work is drawn with a dashed outline, finished work with a
   solid one, so you can read the state of a project before the label */
.feat.is-wip { border-style: dashed; }
.row.is-wip { border-top-style: dashed; }
.row.is-wip .row-kind { border-style: dashed; }

.feat h3 {
  font-size: clamp(1.25rem, 2.2vw, 1.6rem);
  font-weight: 700;
  letter-spacing: -.025em;
  /* the squiggle is drawn on only when you go looking at the card */
  text-decoration: underline wavy transparent;
  text-decoration-thickness: 2px;
  text-underline-offset: 8px;
  text-decoration-skip-ink: none;
  transition: text-decoration-color .3s var(--ease);
}
.feat:hover h3 { text-decoration-color: var(--hot); }
.feat > p { margin-top: .75rem; color: var(--mute); font-size: .98rem; }

.feat-points { margin-top: 1.15rem; display: grid; gap: .55rem; }
.feat-points li {
  position: relative;
  padding-left: 1.5rem;
  font-size: .92rem;
  color: var(--mute);
}
.feat-points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .55em;
  width: 9px;
  height: 9px;
  border: 2px solid var(--hot);
  border-radius: 50% 40% 55% 45%;
}

.feat-foot {
  margin-top: auto;
  padding-top: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
}
.stack {
  font-family: var(--mono);
  font-size: .74rem;
  color: var(--faint);
  letter-spacing: .02em;
}
.feat-link {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-height: 44px;
  padding: .4rem .95rem;
  border: 2px solid var(--line-2);
  border-radius: var(--r-pill);
  font-size: .88rem;
  font-weight: 600;
  box-shadow: 0 4px 0 0 var(--line);
  transition: border-color .2s var(--ease), color .2s var(--ease),
              transform .2s var(--ease), box-shadow .2s var(--ease);
}
.feat-link:hover { border-color: var(--hot); color: var(--hot); transform: translateY(-2px); box-shadow: 0 6px 0 0 var(--hot-deep); }
.feat-link:active { transform: translateY(3px); box-shadow: 0 0 0 0 var(--hot-deep); }

/* ── work: index cards ───────────────────────────────────────────── */
.index-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2.5vw, 1.5rem);
}
.idx {
  padding: 1.5rem 1.4rem;
  border: 2px solid var(--line);
  border-radius: var(--r-tile);
  background: rgba(15, 20, 32, .55);
  transition: transform .25s var(--ease), border-color .25s var(--ease), background-color .25s var(--ease);
}
.idx:hover { transform: translateY(-4px); border-color: var(--hot-line); background: var(--panel); }
.idx h4 { margin-top: .9rem; font-size: 1.05rem; font-weight: 700; letter-spacing: -.02em; }
.idx p { margin-top: .55rem; color: var(--mute); font-size: .9rem; }
.idx .stack { display: block; margin-top: 1rem; }
.idx-link {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-height: 44px;
  margin-top: .5rem;
  font-size: .85rem;
  font-weight: 600;
  color: var(--mute);
  transition: color .2s var(--ease);
}
.idx-link:hover { color: var(--hot); }

/* ── work: software and systems, as wide rows ────────────────────── */
.also { margin-top: clamp(3rem, 6vw, 4.5rem); }
.also-head {
  font-family: var(--hand);
  font-size: clamp(1.5rem, 3vw, 2rem);
  font-weight: 700;
  color: var(--chalk);
  transform: rotate(-1deg);
  margin-bottom: 1.75rem;
  text-decoration: underline wavy var(--hot);
  text-decoration-thickness: 2px;
  text-underline-offset: 9px;
  text-decoration-skip-ink: none;
}

.rows { display: grid; }
.row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: start;
  gap: clamp(1.1rem, 3vw, 2rem);
  padding: 1.6rem .25rem;
  border-top: 1px solid var(--line);
  transition: background-color .25s var(--ease);
}
.row:last-child { border-bottom: 1px solid var(--line); }
.row:hover { background: rgba(255, 61, 120, .04); }

.row-ico {
  width: 2.4rem;
  height: 2.4rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--hot);
  transform-box: fill-box;
  transform-origin: center;
  overflow: visible;
  margin-top: .15rem; /* optically level with the row title */
}
@media (prefers-reduced-motion: no-preference) {
  .row:hover .row-ico { animation: wiggle .55s var(--ease); }
}

.row-body h4 {
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: -.02em;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .6rem;
}
.row-kind {
  font-family: var(--mono);
  font-size: .64rem;
  font-weight: 400;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--faint);
  border: 1px solid var(--line-2);
  border-radius: var(--r-pill);
  padding: .18rem .6rem;
}
.row-body p { margin-top: .5rem; color: var(--mute); font-size: .94rem; max-width: 62ch; }
.row-body .stack { display: block; margin-top: .7rem; }

/* ── the companion face, playable in place ───────────────────────── */
.demo {
  grid-column: 1 / -1;
  margin-top: 1.25rem;
  display: grid;
  justify-items: start;
  gap: .9rem;
}

.demo-screen {
  width: 100%;
  max-width: 320px;
  aspect-ratio: 16 / 9;
  background: #05070c;
  border: 2px solid var(--line-2);
  border-radius: var(--r-tile);
  overflow: hidden;
}
.demo-screen canvas { width: 100%; height: 100%; display: block; }

.demo-controls { display: flex; flex-wrap: wrap; gap: .5rem; }
.demo-btn {
  min-height: 44px;
  padding: .45rem 1rem;
  border: 2px solid var(--line-2);
  border-radius: var(--r-pill);
  font-family: var(--mono);
  font-size: .78rem;
  letter-spacing: .06em;
  color: var(--mute);
  transition: color .18s var(--ease), border-color .18s var(--ease),
              background-color .18s var(--ease), transform .18s var(--ease);
}
.demo-btn:hover { color: var(--chalk); border-color: var(--line-2); transform: translateY(-2px); }
.demo-btn:active { transform: translateY(1px); }
.demo-btn.is-on {
  color: var(--hot);
  border-color: var(--hot);
  background: var(--hot-wash);
}

.demo-note { font-size: 1.05rem; transform: rotate(-1.5deg); }

.row-link {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-height: 44px;
  padding: .4rem 1rem;
  border: 2px solid var(--line-2);
  border-radius: var(--r-pill);
  font-size: .88rem;
  font-weight: 600;
  white-space: nowrap;
  box-shadow: 0 4px 0 0 var(--line);
  transition: border-color .2s var(--ease), color .2s var(--ease),
              transform .2s var(--ease), box-shadow .2s var(--ease);
}
.row-link:hover { border-color: var(--hot); color: var(--hot); transform: translateY(-2px); box-shadow: 0 6px 0 0 var(--hot-deep); }
.row-link:active { transform: translateY(3px); box-shadow: 0 0 0 0 var(--hot-deep); }

@media (max-width: 720px) {
  .row { grid-template-columns: auto 1fr; }
  .row-link { grid-column: 1 / -1; justify-self: start; margin-top: .25rem; }
}

/* ── per-card detail toggle, phones only ─────────────────────────── */
/* The bullet lists are most of the height of the work section, so on a
   phone each card hides its own until asked. Visibility is decided in
   CSS, not JS, so resizing the window sorts itself out. */
/* Collapsed at every width, not just on phones. The cards carry real
   engineering detail now, and left open they both bury the summary and
   stretch whichever card shares their row. Closed, all four match. */
.points-btn {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  align-self: flex-start;
  min-height: 44px;
  margin-top: .9rem;
  padding: .35rem .9rem .35rem 0;
  font-family: var(--mono);
  font-size: .74rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--hot);
  background: none;
  border: 0;
}
.points-btn svg {
  width: 15px; height: 15px;
  fill: none; stroke: currentColor; stroke-width: 2.6;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .25s var(--ease);
}
.points-btn:hover { color: var(--chalk); }
.points-btn[aria-expanded="true"] svg { transform: rotate(180deg); }

.feat .feat-points { display: none; }
.feat.points-open .feat-points { display: grid; }

/* ── show more, on small screens only ────────────────────────────── */
/* The full list of builds is a long scroll on a phone, so the compact ones
   collapse to the first two THERE ONLY. The breakpoint lives here, in CSS,
   never in JS: driving it from script.js let the collapsed state leak onto
   desktop whenever a resize event was missed. JS only toggles .show-all. */
.more-btn { display: none; }

@media (max-width: 720px) {
  .index-grid:not(.show-all) .idx:nth-child(n + 3) { display: none; }
  .more-btn { display: flex; }
}

.more-btn {
  align-items: center;
  justify-content: center;
  gap: .55rem;
  width: 100%;
  min-height: 48px;
  margin-top: 1.1rem;
  padding: .8rem 1.4rem;
  border: 2px dashed var(--line-2);
  border-radius: var(--r-pill);
  font-weight: 600;
  font-size: .95rem;
  color: var(--chalk);
  transition: border-color .2s var(--ease), color .2s var(--ease);
}
.more-btn:hover { border-color: var(--hot); color: var(--hot); }
.more-btn-arrow {
  width: 18px; height: 18px;
  fill: none; stroke: currentColor; stroke-width: 2.4;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .25s var(--ease);
}
.more-btn[aria-expanded="true"] .more-btn-arrow { transform: rotate(180deg); }

/* ── wins ────────────────────────────────────────────────────────── */
.wins {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 3.5vw, 2.5rem);
  padding-top: 1.25rem;
}
.win {
  position: relative;
  padding: 2.2rem 1.7rem 1.9rem;
  background: var(--panel);
  border: 2px solid var(--line);
  border-radius: var(--r-doodle);
  transition: transform .28s var(--ease), border-color .28s var(--ease);
}
.win:nth-child(1) { transform: rotate(-1.6deg); }
.win:nth-child(2) { transform: rotate(.9deg) translateY(1.5rem); border-radius: var(--r-doodle-b); }
.win:nth-child(3) { transform: rotate(-.7deg); }
.win:hover { transform: rotate(0) translateY(-5px); border-color: var(--hot-line); }

/* strip of tape holding the note to the page */
.tape {
  position: absolute;
  top: -13px;
  left: 50%;
  width: 86px;
  height: 26px;
  transform: translateX(-50%) rotate(-3deg);
  background: rgba(255, 61, 120, .17);
  border: 1px solid rgba(255, 61, 120, .3);
  border-radius: 3px;
}

.win-where {
  display: block;
  margin-top: 1rem;
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--faint);
}
.win h3 { margin-top: .5rem; font-size: 1.2rem; font-weight: 700; letter-spacing: -.02em; }
.win p { margin-top: .7rem; color: var(--mute); font-size: .92rem; }

/* ── journey ─────────────────────────────────────────────────────── */
.road { position: relative; display: grid; gap: 2.5rem; padding-left: 2.5rem; max-width: 52rem; }
.road::before {
  content: "";
  position: absolute;
  left: 7px;
  top: .6rem;
  bottom: .6rem;
  width: 0;
  border-left: 3px dashed var(--line-2);
}
.stop { position: relative; }
.stop::before {
  content: "";
  position: absolute;
  left: -2.5rem;
  top: .45rem;
  width: 17px;
  height: 17px;
  border: 3px solid var(--hot);
  border-radius: 52% 44% 56% 48%;
  background: var(--ink);
}
.stop-when {
  font-family: var(--mono);
  font-size: .75rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--hot);
}
.stop h3 { margin-top: .45rem; font-size: 1.35rem; font-weight: 700; letter-spacing: -.025em; }
.stop-where { display: block; margin-top: .25rem; color: var(--faint); font-size: .92rem; }
.stop p { margin-top: .85rem; color: var(--mute); max-width: 56ch; font-size: .98rem; }

/* ── contact ─────────────────────────────────────────────────────── */
.contact-inner { text-align: center; display: grid; justify-items: center; }
.contact-doodle {
  width: clamp(140px, 22vw, 200px);
  fill: none;
  stroke: var(--hot);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .5;
  margin-bottom: 1.5rem;
  overflow: visible;
}
.contact-title { text-wrap: balance; }
.contact-text { margin-top: 1.25rem; max-width: 46ch; color: var(--mute); }
.contact-cta { display: flex; flex-wrap: wrap; justify-content: center; gap: .9rem; margin-top: 2.2rem; }
/* the address IS the call to action, so there is nothing to guess at */
.btn-mail {
  font-family: var(--mono);
  font-size: clamp(.82rem, 2.4vw, .95rem);
  letter-spacing: -.01em;
}

.contact-where {
  margin-top: 2.2rem;
  font-family: var(--mono);
  font-size: .78rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ═══════════════════════════════════════════════════════════════════
   THE LITTLE ONE
   A second, smaller robot that lives in the margin and entertains
   itself: it picks an activity, does it, gets bored, picks another.
   Same procedural face as the hero, driven by script.js.
   ═══════════════════════════════════════════════════════════════════ */
.buddy {
  position: fixed;
  left: 0;
  bottom: -12px;
  z-index: 80;
  width: 104px;
  display: grid;
  justify-items: center;
  /* it walks by translating along the bottom of the viewport; script.js
     sets the distance and works out how long the trip should take */
  transform: translate(var(--bx, 24px), var(--by, 0px));
  transition: transform var(--walk-dur, 3s) linear;
  opacity: 0;
  transition: transform var(--walk-dur, 3s) linear, opacity .35s var(--ease);
}
/* it only exists once the one in the hero has climbed out of frame */
.buddy.freed { opacity: 1; }
/* The drop is a ONE-SHOT class that script.js removes when it finishes.
   As a permanent `.freed` rule it replayed its scale every time you
   scrolled back past the hero, and it also masked the idle breathing. */
.buddy.dropping .buddy-stage { animation: buddy-drop .55s var(--ease) backwards; }
@keyframes buddy-drop {
  0%   { transform: translateY(-70px) scale(.7); opacity: 0; }
  70%  { transform: translateY(6px) scale(1.05); opacity: 1; }
  100% { transform: none; opacity: 1; }
}

.buddy-stage { position: relative; width: 100%; }

/* Its ground shadow sits OUTSIDE the stage, so the body can bob and walk
   above it while the shadow stays on the floor where it belongs. */
/* No drawn ground for this one: it walks on the bottom edge of the window,
   so the edge of the screen is the floor. The -12px offsets the blank space
   the viewBox leaves under its feet, putting the soles exactly on the edge. */

/* It is decorative and the page is not. When it wanders over a button or a
   link it fades right back and stops taking clicks, so it can never sit on
   top of a call to action or swallow a tap meant for one. */
.buddy.shy { opacity: .14; pointer-events: none; }

.buddy-bot {
  width: 100%;
  height: auto;
  fill: none;
  stroke: var(--chalk);
  stroke-width: 5;
  stroke-linecap: round;
  stroke-linejoin: round;
  overflow: visible;
  opacity: .85;
}
.bd-head, .bd-body { fill: var(--panel); }
.bd-chip { fill: var(--hot-wash); stroke: var(--hot); }
.bd-bulb { fill: var(--hot); stroke: var(--hot); }

/* its screen, running the same face as everything else */
/* same drawing as the hero robot, so the same screen percentages */
.buddy-face {
  position: absolute;
  left: 25.5%;
  top: 21.7%;
  width: 49%;
  height: 21.3%;
  pointer-events: none;
}

.buddy-prop {
  position: absolute;
  top: -6px;
  right: -10px;
  width: 26px;
  height: 26px;
  fill: none;
  stroke: var(--hot);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
  transform: scale(.5);
  transition: opacity .3s var(--ease), transform .3s var(--ease);
  overflow: visible;
}
.buddy.has-prop .buddy-prop { opacity: 1; transform: scale(1); }

.buddy-bubble {
  min-height: 1.4em;
  margin-bottom: .3rem;
  padding: .3rem .7rem;
  font-size: .95rem;
  line-height: 1.25;
  text-align: center;
  white-space: nowrap;
  background: var(--panel);
  border: 2px solid var(--hot-line);
  border-radius: 14px 16px 14px 4px;
  opacity: 0;
  transform: translateY(6px) scale(.9);
  transition: opacity .28s var(--ease), transform .28s var(--ease);
  pointer-events: none;
}
.buddy.talking .buddy-bubble { opacity: 1; transform: none; }

/* ── walking ─────────────────────────────────────────────────────── */
/* a bob and a lean in the direction of travel. It is a symmetric little
   thing, so leaning reads as walking far better than mirroring it would. */
.buddy.walking .buddy-stage { animation: bd-walk .46s ease-in-out infinite; }
@keyframes bd-walk {
  0%, 100% { transform: translateY(0) }
  50%      { transform: translateY(-7px) }
}
.buddy-bot { transition: transform .45s var(--ease); transform: rotate(var(--lean, 0deg)); }

/* arms and legs swing in opposition, the way you actually walk */
.bd-arm, .bd-leg { transform-box: fill-box; transform-origin: top center; }
.buddy.walking .bd-arm-l,
.buddy.walking .bd-leg-r { animation: bd-swing .46s ease-in-out infinite alternate; }
.buddy.walking .bd-arm-r,
.buddy.walking .bd-leg-l { animation: bd-swing .46s ease-in-out infinite alternate-reverse; }
@keyframes bd-swing { from { transform: rotate(-13deg) } to { transform: rotate(13deg) } }

/* legs take a bigger stride than the arms do */
.buddy.walking .bd-leg-l,
.buddy.walking .bd-leg-r { animation-name: bd-step; }
@keyframes bd-step { from { transform: rotate(-19deg) } to { transform: rotate(19deg) } }

/* ── being picked up ─────────────────────────────────────────────── */
.buddy-stage { cursor: grab; touch-action: none; }
.buddy.grabbed { cursor: grabbing; z-index: 95; }
.buddy.grabbed .buddy-stage { cursor: grabbing; animation: bd-dangle .8s ease-in-out infinite; }
@keyframes bd-dangle { 0%, 100% { transform: rotate(-5deg) } 50% { transform: rotate(5deg) } }

/* limbs hang and sway while it is held off the ground */
.buddy.grabbed .bd-arm-l,
.buddy.grabbed .bd-leg-l { animation: bd-hang .9s ease-in-out infinite alternate; }
.buddy.grabbed .bd-arm-r,
.buddy.grabbed .bd-leg-r { animation: bd-hang .9s ease-in-out infinite alternate-reverse; }
@keyframes bd-hang { from { transform: rotate(-9deg) } to { transform: rotate(9deg) } }

/* ── climbing the edges of the window ────────────────────────────── */
/* This failed the first time because it clung to an imaginary wall in the
   middle of the page. Now it walks to the actual left or right edge of the
   window and climbs THAT, the same way the bottom edge is its floor, so
   there is a real boundary for it to be holding on to. */
.buddy-stage { transition: transform .3s var(--ease); }
.buddy.climbing .buddy-stage { animation: bd-climb .55s ease-in-out infinite; }
@keyframes bd-climb {
  0%, 100% { transform: rotate(var(--climb-rot, 0deg)) translateY(0); }
  50%      { transform: rotate(var(--climb-rot, 0deg)) translateY(-5px); }
}

/* big alternating hauls rather than a walking swing */
.buddy.climbing .bd-arm-l,
.buddy.climbing .bd-leg-r { animation: bd-haul .55s ease-in-out infinite alternate; }
.buddy.climbing .bd-arm-r,
.buddy.climbing .bd-leg-l { animation: bd-haul .55s ease-in-out infinite alternate-reverse; }
@keyframes bd-haul { from { transform: rotate(-34deg) } to { transform: rotate(26deg) } }

/* ── what it gets up to ──────────────────────────────────────────── */
.buddy-stage { animation: bd-breathe 4s ease-in-out infinite; }
@keyframes bd-breathe { 0%, 100% { transform: translateY(0) } 50% { transform: translateY(-4px) } }

/* A clean jump, no squash. The scaleY read as the robot changing size
   rather than as cartoon weight. */
.buddy.act-hop .buddy-stage { animation: bd-hop .55s var(--ease) 2; }
@keyframes bd-hop {
  0%, 100% { transform: translateY(0); }
  30%      { transform: translateY(-17px); }
}

.buddy.act-wave .bd-arm-r { animation: bd-wave .5s ease-in-out 4; transform-box: fill-box; transform-origin: top left; }
@keyframes bd-wave { 0%, 100% { transform: rotate(0) } 50% { transform: rotate(-24deg) } }

.buddy.act-solder .bd-arm-r { animation: bd-poke .32s ease-in-out 6; transform-box: fill-box; transform-origin: top left; }
@keyframes bd-poke { 0%, 100% { transform: rotate(0) } 50% { transform: rotate(12deg) translateY(3px) } }

.buddy.act-ponder .buddy-stage { animation: bd-tilt 1.4s ease-in-out 2; }
@keyframes bd-tilt { 0%, 100% { transform: rotate(0) } 30% { transform: rotate(-7deg) } 70% { transform: rotate(5deg) } }

.buddy.act-snooze .buddy-bot { opacity: .55; }
.buddy.act-snooze .buddy-prop { animation: bd-float 2s ease-in-out infinite; }
@keyframes bd-float {
  0%   { transform: translate(0, 0) scale(.8); opacity: .3; }
  50%  { transform: translate(6px, -10px) scale(1); opacity: 1; }
  100% { transform: translate(12px, -20px) scale(.8); opacity: 0; }
}

.buddy.act-spark .buddy-prop { animation: bd-zap .4s steps(2) 5; }
@keyframes bd-zap { 0%, 100% { opacity: 1; transform: scale(1) } 50% { opacity: .25; transform: scale(1.3) } }

/* it is decorative, so it does not follow you onto a small screen and it
   sits out entirely when motion is unwelcome */
@media (max-width: 900px) { .buddy { display: none; } }
@media (prefers-reduced-motion: reduce) { .buddy { display: none; } }

/* ── footer ──────────────────────────────────────────────────────── */
.foot { border-top: 1px solid var(--line); padding-block: 2.5rem; }
.foot-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 1.5rem;
  justify-content: space-between;
  align-items: center;
}
.foot p { font-size: .85rem; color: var(--mute); }
.foot-note { color: var(--faint); }
.foot-meta { display: grid; gap: .2rem; text-align: right; }

/* signed off by hand */
.foot-motto {
  font-size: clamp(1.3rem, 3vw, 1.75rem);
  transform: rotate(-2deg);
}

@media (max-width: 560px) {
  .foot-inner { justify-content: center; text-align: center; }
  .foot-meta { text-align: center; justify-items: center; }
}

/* ── scroll reveal ───────────────────────────────────────────────── */
.reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}
.reveal.seen { opacity: 1; transform: none; }
/* keep the deliberate layout offsets once the reveal lands */
.panel.reveal.seen:nth-child(2),
.panel.reveal.seen:nth-child(3) { transform: translateY(1.75rem); }
.win.reveal.seen:nth-child(1) { transform: rotate(-1.6deg); }
.win.reveal.seen:nth-child(2) { transform: rotate(.9deg) translateY(1.5rem); }
.win.reveal.seen:nth-child(3) { transform: rotate(-.7deg); }

/* ═══════════════════════════════════════════════════════════════════
   MOTION
   The through-line: this is a sketchbook, so the drawings draw
   themselves. Every animation below is either that idea, feedback on
   an action, or sequencing that matches how you read the page.
   ═══════════════════════════════════════════════════════════════════ */

/* hero entrance, sequenced top to bottom the way it reads */
@media (prefers-reduced-motion: no-preference) {
  .hero-hi    { animation: rise-tilt .85s var(--ease) .15s backwards; }
  .hero-title { animation: rise .85s var(--ease) .28s backwards; }
  .hero-sub   { animation: rise .85s var(--ease) .46s backwards; }
  .hero-cta   { animation: rise .85s var(--ease) .6s backwards; }
  .bot-say    { animation: pop-say .6s var(--ease) 1.9s backwards; }
}

@keyframes rise      { from { opacity: 0; transform: translateY(20px); } }
@keyframes rise-tilt {
  from { opacity: 0; transform: translateY(20px) rotate(-2.5deg); }
  to   { opacity: 1; transform: rotate(-2.5deg); }
}
@keyframes pop-say {
  0%   { opacity: 0; transform: rotate(-8deg) scale(.4); }
  70%  { opacity: 1; transform: rotate(-8deg) scale(1.12); }
  100% { opacity: 1; transform: rotate(-8deg) scale(1); }
}

/* icons react when you hover the thing they belong to */
.panel-ico, .feat-ico, .idx-ico, .win-ico {
  transform-box: fill-box;
  transform-origin: center;
}
@media (prefers-reduced-motion: no-preference) {
  .panel:hover .panel-ico,
  .feat:hover .feat-ico,
  .idx:hover .idx-ico,
  .win:hover .win-ico { animation: wiggle .55s var(--ease); }
}
@keyframes wiggle {
  0%, 100% { transform: rotate(0) scale(1); }
  30%      { transform: rotate(-10deg) scale(1.1); }
  65%      { transform: rotate(8deg) scale(1.1); }
}

/* sticky notes land like they were stuck down, not faded in */
.note.reveal { transform: translateY(22px) scale(.94); }
.note.reveal.seen { animation: stamp .6s var(--ease) backwards; }
.note-a.reveal.seen { transform: rotate(-2.2deg); }
.note-b.reveal.seen { transform: rotate(1.8deg); }
.note-c.reveal.seen { transform: rotate(1.4deg); }
.note-d.reveal.seen { transform: rotate(-1.6deg); }
@keyframes stamp {
  0%  { opacity: 0; transform: translateY(22px) scale(.94); }
  60% { opacity: 1; transform: scale(1.03); }
}

/* chips pop in one after another, left to right */
@media (prefers-reduced-motion: no-preference) {
  .cluster.seen .chip { animation: pop .45s var(--ease) backwards; }
  .chips .chip:nth-child(1) { animation-delay: .05s; }
  .chips .chip:nth-child(2) { animation-delay: .11s; }
  .chips .chip:nth-child(3) { animation-delay: .17s; }
  .chips .chip:nth-child(4) { animation-delay: .23s; }
  .chips .chip:nth-child(5) { animation-delay: .29s; }
  .chips .chip:nth-child(6) { animation-delay: .35s; }
}
@keyframes pop {
  from { opacity: 0; transform: translateY(10px) scale(.9); }
}

/* the timeline draws itself downward as you reach it */
.road::before {
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 1.2s var(--ease);
}
.road.drawn::before { transform: scaleY(1); }

/* pause the marquee so a reader can actually catch a word */
.marquee:hover .marquee-track,
.marquee:focus-within .marquee-track { animation-play-state: paused; }

/* ═══ responsive ═══════════════════════════════════════════════════ */
@media (max-width: 1024px) {
  /* copy leads on tablet so the headline and CTAs stay above the fold */
  .hero-grid { grid-template-columns: 1fr; gap: 2rem; justify-items: start; }
  .hero-bot { max-width: 210px; justify-self: center; }
  .about-grid { grid-template-columns: 1fr; }
  .index-grid { grid-template-columns: repeat(2, 1fr); }
  .wins { grid-template-columns: 1fr; }
  .win:nth-child(2),
  .win.reveal.seen:nth-child(2) { transform: rotate(.9deg); }
  .feat-lead { grid-row: auto; }
}

@media (max-width: 860px) {
  /* the capsule keeps its shape and the menu drops out of it as its own card */
  .nav { padding-inline: 1rem; }
  .nav-pill { width: 100%; justify-content: space-between; padding-right: .35rem; }

  .nav-links {
    position: absolute;
    top: calc(100% + .6rem);
    left: 0;
    right: 0;
    z-index: var(--z-menu);
    flex-direction: column;
    align-items: stretch;
    gap: .15rem;
    margin: 0;
    padding: .6rem;
    border-left: 0;
    /* Solid, and deliberately no backdrop-filter: the pill above is already
       a backdrop root, and nesting a second one makes this panel composite
       as though it were see-through. */
    background: #0b0f19;
    border: 1px solid var(--line-2);
    border-radius: 1.6rem;
    box-shadow: 0 20px 50px rgba(0, 0, 0, .6);
    transform: translateY(-12px) scale(.97);
    opacity: 0;
    visibility: hidden;
    transition: transform .28s var(--ease), opacity .28s var(--ease), visibility .28s;
  }
  .nav-links.open { transform: none; opacity: 1; visibility: visible; }
  .nav-links a { padding: .85rem 1rem; font-size: 1.02rem; border-radius: 1rem; }
  .burger { display: flex; }
  .nav-cta { display: none; }
}

@media (max-width: 720px) {
  body { font-size: 1rem; }
  .panels, .clusters, .feature-grid, .index-grid { grid-template-columns: 1fr; }
  .panel:nth-child(2), .panel:nth-child(3),
  .panel.reveal.seen:nth-child(2), .panel.reveal.seen:nth-child(3) { transform: none; }
  .note-b, .note-d { margin-top: 0; }
  .scribble-arrow { display: none; }
  .road { padding-left: 1.9rem; }
  .stop::before { left: -1.9rem; }
  .hero-bot { max-width: 240px; }
  .bot-say { font-size: 1.1rem; }
}

@media (max-width: 420px) {
  .notes { grid-template-columns: 1fr; }
  .btn { width: 100%; }
  .hero-cta, .contact-cta { width: 100%; }
}

/* ═══ reduced motion ═══════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .marquee-track { animation: none; }
  .reveal, .note.reveal { opacity: 1; transform: none; }
  .bot, .bot-bulb, .bot-spark { animation: none; }
  .road::before { transform: none; transition: none; }
  .note-a.reveal, .note-a.reveal.seen { transform: rotate(-2.2deg); }
  .note-b.reveal, .note-b.reveal.seen { transform: rotate(1.8deg); }
  .note-c.reveal, .note-c.reveal.seen { transform: rotate(1.4deg); }
  .note-d.reveal, .note-d.reveal.seen { transform: rotate(-1.6deg); }
}
