/* ---------- Tokens ---------- */
:root {
  --ink: #06080f;
  --paper: #f3f1ec;
  --accent: #5b4bff;
  --accent-ink: #4a3ae0; /* accent as text on paper */
  --accent-2: #7dffe9;
  --pink: #c04dff;
  --cyan: #6fd6ff; /* blueprint chapter only */
  --cream: #f4f1ea; /* text */
  --dim: rgba(244,241,234,.68); /* secondary text */
  --card: #05060a;  /* card surface: near-black, so section glows show in the gaps between cards */
  --line: rgba(255,255,255,.09); /* card edge and dividers */
  --accent-soft: #b3a8ff; /* accent as text and small marks on dark */
  /* One brand gradient, taken from the logo: violet to magenta. */
  --grad: linear-gradient(100deg, #4a3aff, #b23cff); /* exactly the logo's two colours */

  /* Page gutter; beyond 90rem the content column stops growing. */
  --gutter: max(clamp(1.25rem, 5vw, 5rem), calc((100vw - 90rem) / 2));
  --section: clamp(4.5rem, 8vw, 7rem); /* padding above and below every section; the same value separates the footer links */
  --fade: clamp(8rem, 22vh, 16rem);    /* distance over which a section backdrop fades in and out */

  /* Radius scale. The 3D scene keeps its own px radii: it is a fixed design box scaled as a whole. */
  --r-sm: 8px;
  --r-md: 16px;  /* media inside a card */
  --r-lg: 28px;  /* cards */
  --r-pill: 999px;

  /* Mono label scale */
  --label: .78rem;  /* section / card eyebrows */
  --micro: .74rem;  /* tags, captions, fine print */
  --track: .14em;

  --ease: cubic-bezier(.2,.8,.2,1);
  --sans: "SF Pro Display", -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, system-ui, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.55;
  --label-color: var(--accent-soft); --focus: var(--accent-soft);
  color: var(--cream);
  background: var(--ink);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, p, ul, ol, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--focus, var(--accent)); outline-offset: 3px; border-radius: 4px; }

.skip {
  position: fixed; left: 1rem; top: -4rem; z-index: 100;
  padding: .6rem 1rem; background: var(--paper); color: var(--ink); border-radius: var(--r-sm);
}
.skip:focus { top: 1rem; }

.num, .eyebrow, .proj-kind, .skill-grid h3, .foot-grid h3 {
  font: var(--label) var(--mono); letter-spacing: var(--track); text-transform: uppercase;
}
.num, .eyebrow { color: var(--label-color); }
.tags { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: 1.25rem; }
.tags li {
  font: var(--micro) var(--mono); letter-spacing: .02em;
  padding: .3rem .65rem; border: 1px solid color-mix(in srgb, currentColor 28%, transparent); border-radius: var(--r-pill);
}
.btn {
  display: inline-block; padding: .85rem 1.4rem; border-radius: var(--r-pill);
  background: var(--grad); color: #fff; font-weight: 600; text-decoration: none;
  transition: transform .25s var(--ease), filter .25s, background-color .25s, box-shadow .25s;
}
.btn:hover { transform: translateY(-2px); filter: brightness(1.12); }
.btn:active { transform: translateY(0) scale(.98); transition-duration: .08s; }
.btn-ghost { background: transparent; color: inherit; box-shadow: inset 0 0 0 1px rgba(255,255,255,.35); }
.btn-ghost:hover { background: rgba(255,255,255,.1); filter: none; }

/* ---------- Nav ---------- */
/* Transparent over the hero; condenses into a floating glass pill once you scroll. */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.1rem var(--gutter); color: #fff; border-radius: var(--r-pill);
  transition: top .5s var(--ease), left .5s var(--ease), right .5s var(--ease),
    padding .5s var(--ease), background .4s, box-shadow .4s, color .4s;
}
.nav.is-stuck {
  top: .75rem; left: max(.75rem, calc(50% - 27rem)); right: max(.75rem, calc(50% - 27rem));
  padding: .45rem .67rem 0.45rem 0.5rem;
  /* Dark glass: whatever scrolls underneath (a white screenshot included) is dimmed and blurred
     enough that the links keep their contrast. */
  background: rgba(10,11,22,.8); -webkit-backdrop-filter: blur(1.25rem) saturate(1.5); backdrop-filter: blur(1.25rem) saturate(1.5);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.14), 0 14px 40px rgba(0,0,0,.35);
}
/* Page progress: a ring that fills around the UB mark as you scroll. */
@property --p { syntax: "<number>"; inherits: false; initial-value: 0; }
@keyframes ring { to { --p: 100; } }
.nav.is-stuck .nav-mark {
  position: relative; display: grid; place-items: center; width: 2.75rem; height: 2.75rem;
}
.nav.is-stuck .nav-mark::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  /* The filled arc runs violet -> magenta -> violet, so its two ends are the same colour and it closes
     without a seam when the page reaches the bottom. Only the faint track adapts to the surface. */
  background: conic-gradient(#8a7bff, var(--pink) calc(var(--p) * .5%), #8a7bff calc(var(--p) * 1%), var(--ring-track, rgba(255,255,255,.28)) 0);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3.5px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3.5px));
}
@supports (animation-timeline: scroll()) {
  .nav.is-stuck .nav-mark::before { animation: ring linear both; animation-timeline: scroll(root); }
}
.nav-mark {
  transition: transform .35s var(--ease), color .3s;
}
.nav-mark:hover { transform: rotate(-8deg) scale(1.15); }
/* A wide, faint glow in the logo's own violet. It is ambient light, kept weak enough that the letter
   edges stay crisp; at the small in-ring size it is dropped, where any blur costs legibility. */
.nav-mark svg { overflow: visible; filter: drop-shadow(0 0 .75rem rgba(150,80,255,.38)); transition: width .5s var(--ease), filter .4s; }
.nav.is-stuck .nav-mark svg { filter: none; }
.nav-mark svg { display: block; width: 2.5rem; height: auto; fill: none; stroke-width: 6.5; stroke-linecap: round; stroke-linejoin: round; transition: width .5s var(--ease); }
.nav.is-stuck .nav-mark svg { width: 1.45rem; } /* sits inside the progress ring */
.nav nav { display: flex; align-items: center; gap: .15rem; }
.nav nav a {
  position: relative; padding: .5rem .9rem; border-radius: var(--r-pill); font-size: .88rem; text-decoration: none;
  color: rgba(255,255,255,.78); transition: color .25s, background .25s, transform .25s;
}
.nav nav a:not(.nav-cta)::after { /* dot that grows in on hover / marks the current section */
  content: ""; position: absolute; left: 50%; bottom: .12rem; width: 4px; height: 4px; margin-left: -2px; border-radius: 50%;
  background: var(--accent-soft); transform: scale(0); transition: transform .3s var(--ease);
}
.nav nav a:hover { color: #fff; background: rgba(255,255,255,.12); }
.nav nav a:hover::after, .nav nav a[aria-current]::after { transform: scale(1); }
.nav nav a[aria-current] { color: #fff; }
.nav nav .nav-cta { margin-left: .5rem; background: var(--grad); color: #fff; font-weight: 600; }
.nav nav .nav-cta:hover { background: var(--grad); filter: brightness(1.12); transform: translateY(-1px); box-shadow: 0 8px 24px rgba(140,70,255,.5); }
.nav-sentinel { position: absolute; top: 0; left: 0; width: 1px; height: 45vh; pointer-events: none; }

/* ---------- Story: static baseline (no JS / reduced motion) ---------- */
.story {
  --fg: var(--cream); --muted: rgba(244,241,234,.68);
  position: relative;
}
.stage { position: relative; min-height: 100svh; overflow: hidden; display: flex; }
.bgs, .bg { position: absolute; inset: 0; }
.bgs { -webkit-mask-image: linear-gradient(#000 calc(100% - var(--fade)), transparent); mask-image: linear-gradient(#000 calc(100% - var(--fade)), transparent); }
.bg { opacity: 0; }
/* Story backdrops use the same recipe as the rest of the site: colour glows on the near-black canvas.
   Each chapter keeps its own tint, so the backdrop still shifts as the story moves on. */
.bg-a {
  opacity: 1;
  background:
    radial-gradient(60% 58% at 86% 6%, rgba(74,58,255,.5), transparent 70%),
    radial-gradient(48% 50% at 62% 58%, rgba(108,92,255,.22), transparent 70%),
    radial-gradient(52% 48% at 0% 62%, rgba(178,60,255,.26), transparent 70%),
    radial-gradient(60% 45% at 100% 100%, rgba(74,58,255,.34), transparent 70%),
    var(--ink);
}
.bg-b { /* architecture: blueprint grid, blue glow */
  background:
    linear-gradient(rgba(140,160,255,.08) 1px, transparent 1px) 0 0 / 48px 48px,
    linear-gradient(90deg, rgba(140,160,255,.08) 1px, transparent 1px) 0 0 / 48px 48px,
    radial-gradient(58% 60% at 72% 48%, rgba(61,139,255,.42), transparent 70%),
    radial-gradient(50% 45% at 0% 100%, rgba(74,58,255,.3), transparent 70%),
    var(--ink);
}
.bg-c { /* build: magenta and violet */
  background:
    radial-gradient(58% 62% at 70% 44%, rgba(178,60,255,.36), transparent 70%),
    radial-gradient(50% 50% at 100% 0%, rgba(74,58,255,.42), transparent 70%),
    radial-gradient(45% 45% at 0% 90%, rgba(74,58,255,.24), transparent 70%),
    var(--ink);
}
.bg-d { /* connect: the one teal moment, as a glow rather than a full wash */
  background:
    radial-gradient(52% 58% at 70% 50%, rgba(18,163,148,.42), transparent 70%),
    radial-gradient(50% 50% at 100% 0%, rgba(74,58,255,.34), transparent 70%),
    radial-gradient(45% 45% at 0% 95%, rgba(74,58,255,.22), transparent 70%),
    var(--ink);
}
.bg-e { /* evidence: the same glows as the Work section it hands off to */
  background:
    radial-gradient(60% 55% at 78% 46%, rgba(74,58,255,.44), transparent 70%),
    radial-gradient(50% 45% at 0% 70%, rgba(178,60,255,.24), transparent 70%),
    var(--ink);
}

.scene { display: none; }

.hero {
  position: relative; z-index: 2; align-self: center;
  width: 100%; padding: 6rem var(--gutter) 4rem;
}
.hero h1 {
  margin: 1rem 0 1.5rem;
  font-size: clamp(3.6rem, 10.5vw, 10.5rem); line-height: .86; letter-spacing: -.055em; font-weight: 800;
}
.hero h1 span { display: block; transform-origin: left center; }
.hero-lede { max-width: 34rem; font-size: clamp(1.02rem, 1.35vw, 1.25rem); color: var(--muted); }
.hero-cta { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 2rem; }
.rail { display: none; }

.step { padding: 3.5rem var(--gutter); }
.step-in { max-width: 31rem; }
.step h2 { margin: .9rem 0 1rem; font-size: clamp(2rem, 4.2vw, 3.6rem); line-height: 1; letter-spacing: -.035em; }
.step p { color: var(--muted); }
.step .btn { margin-top: 1.5rem; }
.facts { display: flex; gap: 2rem; margin-top: 1.75rem; font-family: var(--mono); font-size: .78rem; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); }
.facts b { display: block; font-family: var(--sans); font-size: 2.2rem; letter-spacing: -.03em; color: var(--fg); }

/* ---------- Story: pinned, scroll-driven mode ---------- */
.motion .stage { position: sticky; top: 0; height: 100svh; min-height: 0; }
.motion .steps { position: relative; z-index: 3; margin-top: -100svh; pointer-events: none; }
.motion .spacer { height: 100svh; }
.motion .step { min-height: 100svh; display: flex; align-items: center; padding-block: 0; }
.motion .step-in { pointer-events: auto; will-change: opacity; max-width: min(31rem, 38vw); }

.motion .hero { position: absolute; inset: 0; align-self: stretch; display: flex; flex-direction: column; justify-content: center; max-width: 60rem; will-change: opacity; }
.motion .hero-lede { max-width: min(34rem, 40vw); }
.motion .hero.is-gone { visibility: hidden; }
.motion .hero h1 span { will-change: transform; }
.motion .rail {
  display: flex; flex-direction: column; gap: .35rem;
  position: absolute; right: calc(var(--gutter) / 2.4); top: 50%; z-index: 4; transform: translateY(-50%);
}
.rail a { display: block; padding: .45rem; }
.rail a::before {
  content: ""; display: block; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; opacity: .3; transition: transform .3s, opacity .3s;
}
.rail .on a::before { opacity: 1; transform: scale(1.9); }

/* Scene: a 1000x720 design box, scaled to fit by JS */
.motion .scene { display: block; position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.scene-fit {
  position: absolute; left: 50%; top: 50%; width: 1000px; height: 720px; margin: -360px 0 0 -500px;
  perspective: 1700px; will-change: transform;
}
.tilt { position: absolute; inset: 0; transform-style: preserve-3d; will-change: transform; }
.slab {
  position: absolute; left: 50%; top: 50%; width: 420px; height: 262px; margin: -131px 0 0 -210px;
  will-change: transform;
}
.face {
  position: absolute; inset: 0; border-radius: 22px; overflow: hidden; opacity: 0;
  display: flex; flex-direction: column; justify-content: flex-end; padding: 26px;
  will-change: opacity;
}
.face b { font-size: 44px; line-height: 1; letter-spacing: -.03em; font-weight: 750; }
.face i { margin-top: 8px; font: normal 15px/1.3 var(--mono); opacity: .8; }
.face small { font: 13px var(--mono); letter-spacing: .16em; text-transform: uppercase; opacity: .7; margin-bottom: auto; }

.f-solid {
  background: linear-gradient(135deg, #262c40, #0e111b);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.14), 0 30px 60px rgba(0,0,0,.5);
}
.f-top {
  background: linear-gradient(135deg, #b9b0ff, #6c5cff 52%, var(--pink));
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.35), 0 0 110px rgba(91,75,255,.75);
  padding: 20px; justify-content: space-between; color: var(--ink);
}
.f-top::after { /* slow light sweep across the card */
  content: ""; position: absolute; inset: -20% -60%; pointer-events: none;
  background: linear-gradient(105deg, transparent 42%, rgba(255,255,255,.38) 50%, transparent 58%);
}
.motion .f-top::after { animation: shine 5.5s ease-in-out infinite; }
@keyframes shine { 0%, 55% { transform: translateX(-60%); } 100% { transform: translateX(60%); } }
.id-head { display: flex; align-items: center; gap: 12px; }
.id-mark {
  flex: none; width: 68px; height: 62px; margin: -10px -6px -10px -10px; /* the logo file includes room for its glow */
}
.id-mark img { width: 100%; height: 100%; }
.id-head p { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.face .id-head b { font-size: 23px; letter-spacing: -.03em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.face .id-head i { margin-top: 3px; font-size: 11.5px; opacity: .75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* can never run under the badge */
.id-badge {
  margin-left: auto; align-self: flex-start; flex: none; padding: 6px 11px; border-radius: var(--r-pill); background: rgba(6,8,15,.85); color: #fff;
  font: 11.5px var(--mono); white-space: nowrap;
}
.id-badge::before { content: ""; display: inline-block; width: 7px; height: 7px; margin-right: 7px; border-radius: 50%; background: var(--accent-soft); box-shadow: 0 0 10px var(--accent-soft); }
.id-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.id-stats p {
  display: flex; flex-direction: column; padding: 12px 14px; border-radius: 14px; color: #fff;
  background: rgba(6,8,15,.78); box-shadow: inset 0 0 0 1px rgba(255,255,255,.14);
}
.face .id-stats b { font-size: 34px; letter-spacing: -.04em; }
.face .id-stats i { margin-top: 4px; font-size: 11.5px; text-transform: uppercase; letter-spacing: .12em; opacity: .65; }
.id-foot { display: flex; gap: 7px; }
.id-foot span { padding: 5px 11px; border-radius: var(--r-pill); background: rgba(255,255,255,.32); font: 12px var(--mono); box-shadow: inset 0 0 0 1px rgba(255,255,255,.4); }
.f-solid .edge { color: #fff; font: 15px var(--mono); letter-spacing: .04em; white-space: nowrap; margin: 0 -8px -12px; }
.face .edge b { font: inherit; opacity: .55; margin-right: 6px; }
.face .edge i { display: inline; font: inherit; margin: 0 0 0 10px; opacity: .6; }

.f-wire {
  color: var(--cyan);
  background:
    linear-gradient(rgba(111,214,255,.14) 1px, transparent 1px) 0 0 / 30px 30px,
    linear-gradient(90deg, rgba(111,214,255,.14) 1px, transparent 1px) 0 0 / 30px 30px,
    rgba(10,34,64,.55);
  box-shadow: inset 0 0 0 2px var(--cyan), 0 0 40px rgba(111,214,255,.25);
}

.f-built { color: #fff; box-shadow: inset 0 0 0 1px rgba(255,255,255,.3), 0 30px 70px rgba(0,0,0,.45); }
.f-built svg { width: 64px; height: 64px; margin-bottom: auto; fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.b-web  { background: linear-gradient(140deg, #3d8bff, #1740b8); }
.b-mob  { background: linear-gradient(140deg, #8f6bff, #4420b8); }
.b-back { background: linear-gradient(140deg, #2b3350, #0d101c); }
.b-ai   { background: linear-gradient(140deg, #21c7b3, #0a6a72); }

.f-shot { padding: 0; background: #0b0e22; box-shadow: 0 0 0 1px rgba(255,255,255,.16), 0 30px 70px rgba(0,0,0,.55), 0 0 60px rgba(91,75,255,.25); }
.f-shot img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.f-shot span {
  position: absolute; left: 12px; bottom: 12px; padding: 5px 12px; border-radius: var(--r-pill);
  background: var(--ink); color: #fff; font: 14px var(--mono);
}

.links { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; fill: none; opacity: 0; }
.link-set path { stroke: rgba(255,255,255,.28); stroke-width: 2; stroke-dasharray: 1; stroke-dashoffset: 1; }
.flow-set path { stroke: var(--accent-2); stroke-width: 4; stroke-linecap: round; stroke-dasharray: .03 .17; }
.hub {
  position: absolute; left: 50%; top: 50%; width: 128px; height: 128px; margin: -64px 0 0 -64px; border-radius: 50%;
  display: grid; place-items: center; opacity: 0; color: var(--ink);
  background: radial-gradient(circle at 35% 30%, #fff, var(--accent-2) 45%, #12a394);
  box-shadow: 0 0 0 14px rgba(125,255,233,.14), 0 0 90px rgba(125,255,233,.6);
  font: 700 26px var(--mono); will-change: transform, opacity;
}
.chip {
  position: absolute; left: 50%; top: 50%; opacity: 0; padding: 6px 14px; border-radius: var(--r-pill);
  background: rgba(3,21,26,.85); color: var(--accent-2); box-shadow: inset 0 0 0 1px rgba(125,255,233,.5);
  font: 15px var(--mono); will-change: opacity;
}
.chip-1 { transform: translate(-50%, -50%) translate(-150px, -112px); }
.chip-2 { transform: translate(-50%, -50%) translate(150px, -112px); }
.chip-3 { transform: translate(-50%, -50%) translate(-150px, 112px); }
.chip-4 { transform: translate(-50%, -50%) translate(150px, 112px); }


/* ---------- Hero: layered object, orbiting stack, intro ---------- */
.hero .h1-b { width: fit-content; background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent; padding-bottom: .08em; }
.slab[data-i="0"] .f-solid { background: linear-gradient(135deg, #0f5c66, #06262e); box-shadow: inset 0 0 0 1.5px rgba(125,255,233,.7), 0 40px 90px rgba(0,0,0,.6), 0 0 50px rgba(125,255,233,.25); }
.slab[data-i="1"] .f-solid { background: linear-gradient(135deg, #24348f, #0b1238); box-shadow: inset 0 0 0 1.5px rgba(110,150,255,.75), 0 0 50px rgba(80,120,255,.3); }
.slab[data-i="2"] .f-solid { background: linear-gradient(135deg, #5a2bb5, #1c0b45); box-shadow: inset 0 0 0 1.5px rgba(190,140,255,.8), 0 0 50px rgba(160,90,255,.35); }
.floor {
  position: absolute; left: 50%; top: 50%; width: 1500px; height: 1500px; margin: -750px 0 0 -750px; border-radius: 50%;
  opacity: 0; will-change: opacity, transform;
  background:
    conic-gradient(from 0deg, transparent 0 70%, rgba(125,255,233,.35) 88%, transparent 100%),
    repeating-radial-gradient(circle, transparent 0 78px, rgba(160,150,255,.28) 78px 80px);
  -webkit-mask: radial-gradient(circle, #000 18%, transparent 68%); mask: radial-gradient(circle, #000 18%, transparent 68%);
}
.orbs { display: none; }
.motion .orbs { display: block; position: absolute; inset: 0; }
.orb {
  position: absolute; left: 50%; top: 50%; will-change: transform, opacity;
}
.orb span {
  display: block; padding: 9px 18px; border-radius: var(--r-pill); white-space: nowrap; transform: translate(-50%, -50%);
  font: 17px var(--mono); color: #eceaff;
  background: rgba(20,18,48,.6); box-shadow: inset 0 0 0 1px rgba(170,160,255,.45), 0 10px 30px rgba(0,0,0,.35);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.orb:nth-child(3n) span { color: var(--accent-soft); box-shadow: inset 0 0 0 1px rgba(179,168,255,.55), 0 10px 30px rgba(0,0,0,.35); }
.ticker { display: none; }
.motion .ticker {
  display: flex; position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; overflow: hidden;
  padding: .9rem 0; border-top: 1px solid rgba(255,255,255,.1);
  font: var(--micro) var(--mono); letter-spacing: var(--track); text-transform: uppercase; color: var(--muted); white-space: nowrap;
  will-change: opacity;
}
.ticker ul { display: flex; flex: none; animation: ticker 40s linear infinite; }
.ticker li { padding-right: 3rem; }
.ticker li::before { content: "✦"; margin-right: 3rem; color: var(--accent-soft); }
@keyframes ticker { to { transform: translateX(-100%); } }

/* Idle life + load-in. These use the individual translate/scale properties so they
   compose with the scroll-driven transforms written by main.js. */
.motion .tilt { animation: bob 7s ease-in-out infinite; }
.motion .floor { animation: sweep 14s linear infinite; }
.motion .orb span { animation: drift 6s ease-in-out infinite; }
.motion .orb:nth-child(2n) span { animation-duration: 7.5s; animation-delay: -2s; }
.motion .orb:nth-child(3n) span { animation-duration: 9s; animation-delay: -4s; }
.motion.ready .slab { animation: drop 1.1s var(--ease) both; }
.motion.ready .slab[data-i="1"] { animation-delay: .12s; }
.motion.ready .slab[data-i="2"] { animation-delay: .24s; }
.motion.ready .slab[data-i="3"] { animation-delay: .36s; }
.motion.ready .orbs { animation: fade 1s .9s both; }
.motion:not(.ready) .orbs { visibility: hidden; } /* positioned by main.js */
/* Looping animations only run while they can be seen. */
.story.is-offscreen :is(.tilt, .floor, .orb span, .ticker ul), .story.is-offscreen .f-top::after,
.story.past-hero :is(.floor, .orb span, .ticker ul) { animation-play-state: paused; }
.motion .hero h1 span { animation: rise .9s var(--ease) both; }
.motion .hero .h1-b { animation-delay: .1s; }
.motion .eyebrow, .motion .hero-lede, .motion .hero-cta { animation: rise .9s .25s var(--ease) both; }
.motion .hero-cta { animation-delay: .4s; }
@keyframes bob { 50% { translate: 0 -16px; } }
@keyframes sweep { to { rotate: 360deg; } }
@keyframes drift { 50% { translate: 0 -12px; } }
@keyframes drop { from { translate: 0 0 520px; opacity: 0; } }
@keyframes fade { from { opacity: 0; } }
@keyframes rise { from { translate: 0 70px; opacity: 0; } }

/* Mobile: the visual takes the top of the stage, chapters ride over the bottom */
@media (max-width: 859px) {
  .motion .orbs { display: none; }
  .motion .hero { justify-content: flex-end; padding-bottom: 6.25rem; } /* clears the ticker */
  .motion .hero h1 { font-size: clamp(3.4rem, 19vw, 6rem); }
  .motion .step { align-items: flex-end; padding-bottom: 7svh; }
  .motion .step-in, .motion .hero-lede { max-width: 34rem; } /* keeps a readable measure on tablets */
  .motion .step h2 { font-size: clamp(1.8rem, 8vw, 2.6rem); }
  .motion .step p { font-size: .98rem; }
  .motion .rail { right: .1rem; top: 30%; }
  .nav nav a:nth-child(3), .nav nav a:nth-child(4), .nav nav a:nth-child(5) { display: none; }
  .facts { gap: 1.4rem; margin-top: 1.1rem; }
  .facts b { font-size: 1.7rem; }
}
/* Short phones: tighten the copy so the pinned visual keeps its own space. */
@media (max-width: 859px) and (max-height: 720px) {
  .motion .hero h1 { margin: .6rem 0 .9rem; font-size: clamp(2.8rem, 15vw, 4rem); }
  .motion .hero-lede, .motion .step p { font-size: .92rem; line-height: 1.45; }
  .motion .hero-cta { margin-top: 1.1rem; }
  .motion .hero .btn { padding: .7rem 1.15rem; }
  .motion .step h2 { margin: .6rem 0 .7rem; font-size: clamp(1.6rem, 7vw, 2.2rem); }
  .motion .step .tags, .facts { margin-top: .9rem; }
}

/* ---------- Sections after the story ----------
   One dark canvas. Sections are told apart by colour glows behind them, and all content
   sits in near-black rounded cards arranged in grids. */
.work, .engage, .reviews, .skills, .contact {
  position: relative; isolation: isolate; overflow: hidden; padding: var(--section) var(--gutter);
  scroll-margin-top: 2.5rem; /* anchor jumps leave the section label clear of the floating header */
}


/* Page backdrop. The glows are laid down the full length of the page and scroll with it, alternating
   sides and hues (violet, magenta, blue). They are NOT tied to sections: a glow can sit across a
   section boundary, so there is never an edge where one section's colour stops and the next begins,
   and each stretch of the page still has its own colour. Each glow dies out inside its tile, so the
   tile repeats without a seam. */
body { position: relative; }
body::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(62% 17% at 92% 16%, rgba(74,58,255,.55), transparent 72%),
    radial-gradient(56% 15% at 4% 40%, rgba(178,60,255,.34), transparent 72%),
    radial-gradient(60% 16% at 96% 64%, rgba(61,120,255,.36), transparent 72%),
    radial-gradient(56% 15% at 0% 87%, rgba(108,72,255,.42), transparent 72%);
  background-size: 100% 260vh; background-repeat: repeat-y;
}
.sec-head { max-width: 58rem; margin: 0 auto clamp(2.25rem, 4.5vw, 3.5rem); text-align: center; }
.sec-head h2 { margin-top: .9rem; font-size: clamp(2.2rem, 5.4vw, 4.75rem); line-height: 1.02; letter-spacing: -.04em; text-wrap: balance; }
.sec-lede { max-width: 42rem; margin: 1.5rem auto 0; font-size: 1.15rem; color: var(--dim); }
/* Two-tone headlines: one phrase picked out in the brand gradient */
.hl {
  padding-bottom: .08em; background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}

/* The card: shared by every block below */
.feature, .example, .platforms li, .skill-grid > div, .quote {
  background: var(--card); border-radius: var(--r-lg); box-shadow: inset 0 0 0 1px var(--line);
}

/* Pill label */
.proj-kind {
  width: fit-content; padding: .32rem .75rem; border-radius: var(--r-pill); box-shadow: inset 0 0 0 1px rgba(255,255,255,.2);
  font-size: var(--micro); letter-spacing: .08em; color: rgba(244,241,234,.86);
}

/* Screenshot frame */
.frame { display: block; overflow: hidden; background: #0b0d16; box-shadow: 0 0 0 1px var(--line); }

/* Group label with a rule running to the edge */
.group {
  display: flex; align-items: center; gap: 1rem; margin: clamp(2.5rem, 5vw, 4rem) 0 1.25rem;
  font: var(--label) var(--mono); letter-spacing: var(--track); text-transform: uppercase; color: rgba(244,241,234,.6);
}
.group::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.sec-head + .group { margin-top: 0; }

/* Main projects: two large cards */
.features { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }
.feature {
  position: relative; overflow: hidden; isolation: isolate; display: flex; flex-direction: column;
  min-height: 27rem; padding: clamp(1.75rem, 3.5vw, 3rem);
}
.feature::before { content: ""; position: absolute; inset: 0; z-index: -1; }
.f-stock::before { background: radial-gradient(70% 80% at 100% 0%, rgba(61,139,255,.42), transparent 70%), radial-gradient(50% 60% at 0% 100%, rgba(74,58,255,.2), transparent 70%); }
.f-predict::before { background: radial-gradient(70% 80% at 100% 0%, rgba(91,75,255,.55), transparent 70%), radial-gradient(50% 60% at 0% 100%, rgba(192,77,255,.2), transparent 70%); }
.feature .proj-kind { width: auto; padding: 0; box-shadow: none; font-size: var(--label); letter-spacing: var(--track); line-height: 1.6; color: var(--accent-soft); }
.feature h4 { margin: 1rem 0 1.25rem; font-size: clamp(2.2rem, 4.4vw, 4rem); line-height: 1; letter-spacing: -.04em; overflow-wrap: anywhere; }
.feature blockquote {
  width: fit-content; margin: 0 0 1.1rem; font-size: clamp(1.15rem, 1.8vw, 1.5rem); font-weight: 650; line-height: 1.25; letter-spacing: -.02em;
  color: var(--cream); /* the gradient is kept for headlines and primary actions */
}
.feature .desc { max-width: 34rem; color: var(--dim); }
.feature .tags { margin-bottom: 2rem; }
.feature .actions { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; margin-top: auto; }
/* Store links: platform mark plus the usual two-line label */
.btn-store { display: inline-flex; align-items: center; gap: .65rem; padding: .72rem 1.25rem .72rem 1rem; text-align: left; }
.btn-store svg { flex: none; width: 1.6rem; height: 1.6rem; }
.btn-store span { display: block; font-size: 1.05rem; line-height: 1.15; letter-spacing: -.01em; }
.btn-store small { display: block; font: 500 .62rem var(--sans); letter-spacing: .06em; text-transform: uppercase; opacity: .7; }

/* More examples: a bento grid. Two wide cards, then rows of three. */
.examples { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 1rem; }
.example { position: relative; display: flex; flex-direction: column; grid-column: span 2; padding: 1.25rem 1.25rem 1.5rem; }
.example:nth-child(-n+2) { grid-column: span 3; }
.example > :not(.frame) { margin-inline: .25rem; } /* text sits on (almost) the same left edge as the picture */
.example .frame { margin-bottom: 1.25rem; border-radius: 12px; } /* card radius minus card padding, so the corners nest */
/* Bright pages are toned down a little so they sit in the dark card, and return to full
   brightness on hover. */
.example .frame img { width: 100%; aspect-ratio: 16 / 8.2; object-fit: cover; object-position: top; filter: brightness(.9) saturate(.95); transition: filter .35s, scale .6s var(--ease); }
.example:hover .frame img { filter: none; }
.example h4 { margin-block: .9rem .45rem; font-size: 1.5rem; line-height: 1.1; letter-spacing: -.03em; }
.example:nth-child(-n+2) h4 { font-size: clamp(1.6rem, 2.6vw, 2.2rem); }
.example h4 + p { padding-right: 3.5rem; font-size: .98rem; color: var(--dim); }
/* The title is the card's one link; it is stretched over the whole card so the picture, the text
   and the arrow are all one target. */
.example h4 a { text-decoration: none; outline: none; }
.example h4 a::after { content: ""; position: absolute; inset: 0; border-radius: var(--r-lg); }
.example:has(a:focus-visible) { outline: 2px solid var(--focus); outline-offset: 3px; }
/* Arrow in the card's corner: quiet at rest, filled once the card is the target */
.go {
  position: absolute; right: 1.5rem; bottom: 1.5rem; display: grid; place-items: center; width: 2.5rem; height: 2.5rem; margin: 0 !important;
  border-radius: 50%; box-shadow: inset 0 0 0 1px rgba(255,255,255,.22); color: var(--cream); font-size: 1.15rem; line-height: 1;
  transition: background-color .25s, box-shadow .25s, rotate .35s var(--ease);
}
.example:is(:hover, :focus-within) .go { background: var(--accent); box-shadow: none; color: #fff; rotate: 45deg; }
.also { margin-top: 2rem; text-align: center; font: var(--micro) var(--mono); letter-spacing: .04em; color: var(--dim); }

/* Experience */
.engage-bg { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.engage-bg::before { /* blueprint grid, fading out from the top-right */
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(rgba(140,150,255,.1) 1px, transparent 1px) 0 0 / 56px 56px,
    linear-gradient(90deg, rgba(140,150,255,.1) 1px, transparent 1px) 0 0 / 56px 56px;
  -webkit-mask: radial-gradient(60% 45% at 70% 40%, #000, transparent 75%); mask: radial-gradient(60% 45% at 70% 40%, #000, transparent 75%);
}
.ghost {
  position: absolute; right: -4vw; top: 50%; translate: 0 -55%;
  font-size: 38vw; font-weight: 850; letter-spacing: -.06em; line-height: 1; white-space: nowrap;
  color: transparent; -webkit-text-stroke: 1.5px rgba(170,165,255,.16); will-change: transform;
}
.platforms { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1rem; }
.platforms a { display: flex; flex-direction: column; height: 100%; padding: 1.5rem 1.5rem 1.6rem; border-radius: inherit; text-decoration: none; }
.platforms span { font: var(--micro) var(--mono); color: var(--accent-soft); margin-bottom: clamp(2rem, 5vw, 4.5rem); }
.platforms b { font-size: clamp(1.15rem, 1.9vw, 1.6rem); font-weight: 650; letter-spacing: -.02em; line-height: 1.15; overflow-wrap: break-word; }
.platforms b::after { content: " ↗"; font-weight: 400; color: var(--dim); transition: color .25s; }
.platforms i { margin-top: .5rem; font-style: normal; font-size: .95rem; line-height: 1.45; color: var(--dim); }

/* Marketplace numbers: an open row above the reviews they summarise, not more cards */
.stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: 56rem; margin: 0 auto; text-align: center; }
.stats div { display: flex; flex-direction: column-reverse; justify-content: flex-end; padding: .25rem clamp(.5rem, 2vw, 1.5rem); }
.stats div + div { border-left: 1px solid var(--line); }
.stats dd { font-size: clamp(2.2rem, 6.4vw, 5rem); font-weight: 800; letter-spacing: -.05em; line-height: 1; font-variant-numeric: tabular-nums; }
.stats dt { margin-top: .7rem; font-size: clamp(.8rem, 1.2vw, .95rem); line-height: 1.35; color: var(--dim); }
.fine { margin-top: 2rem; text-align: center; font: var(--micro)/1.7 var(--mono); letter-spacing: .04em; color: var(--dim); }
.stats + .fine { margin-bottom: clamp(2.25rem, 4.5vw, 3.5rem); }

/* Reviews: one lead quote, then a masonry of quote cards */
.quote { margin: 0; padding: 1.6rem 1.6rem 1.4rem; }
.quote blockquote { margin: 0; }
.quote blockquote p + p { margin-top: .8em; }
.quote blockquote { font-size: 1.02rem; line-height: 1.55; color: rgba(244,241,234,.9); overflow-wrap: anywhere; }
.stars { margin-bottom: .9rem; font-size: .85rem; letter-spacing: .18em; color: var(--accent-soft); }
.quote figcaption { display: flex; align-items: center; gap: .75rem; margin-top: 1.25rem; padding-top: 1.1rem; border-top: 1px solid var(--line); }
.av { flex: none; display: grid; place-items: center; width: 2.4rem; height: 2.4rem; border-radius: 50%; background: rgba(179,168,255,.12); box-shadow: inset 0 0 0 1px rgba(179,168,255,.3); color: var(--accent-soft); font-weight: 650; }
.quote figcaption span:last-child { display: flex; flex-direction: column; min-width: 0; }
.quote figcaption b { font-weight: 650; overflow-wrap: anywhere; }
.quote figcaption i { font: normal var(--micro) var(--mono); letter-spacing: .02em; color: var(--dim); }
.quote-lead { margin-bottom: 1rem; padding: clamp(2rem, 5vw, 4rem); text-align: center; }
.quote-lead blockquote { max-width: 46rem; margin-inline: auto; font-size: clamp(1.5rem, 3.2vw, 2.6rem); font-weight: 650; line-height: 1.15; letter-spacing: -.03em; color: var(--cream); text-wrap: balance; }
.quote-lead figcaption { justify-content: center; border-top: 0; padding-top: 0; margin-top: 1.75rem; text-align: left; }
.quotes { columns: 3; column-gap: 1rem; }
.quotes .quote { break-inside: avoid; margin-bottom: 1rem; }
.actions-center { margin-top: 1.5rem; text-align: center; }

/* Skills */
.skill-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; }
.skill-grid > div { padding: 1.75rem 1.75rem 1.4rem; }
.skill-grid h3 { color: var(--accent-soft); margin-bottom: 1rem; }
.skill-grid li { padding: .6rem 0; border-top: 1px solid var(--line); font-size: 1.08rem; }

/* Contact */
.contact { padding-bottom: clamp(2rem, 4vw, 3rem); }
.contact h2 { margin: .9rem 0 2.5rem; font-size: clamp(2.8rem, 9vw, 8.5rem); line-height: .9; letter-spacing: -.05em; transform-origin: left; }
.grad { display: block; width: fit-content; padding-bottom: .08em; background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent; }
.mail {
  display: inline-flex; align-items: center; gap: .9rem; max-width: 100%;
  border-radius: var(--r-pill); background: var(--cream); color: var(--ink);
  font-weight: 650; letter-spacing: -.01em; text-decoration: none;
  overflow-wrap: anywhere; transition: transform .25s var(--ease), box-shadow .25s;
}
.mail::after { content: "→"; transition: transform .25s; }
.mail:hover { transform: translateY(-2px); box-shadow: 0 18px 50px rgba(91,75,255,.55); }
.mail:hover::after { transform: translateX(6px); }
.reach { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem; }
/* The three contact actions share one size so the row sits on a single height. */
.reach > * { padding: 1.05rem 1.5rem; font-size: clamp(1rem, 1.6vw, 1.2rem); line-height: 1.3; }
.foot-grid {
  display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: 2.5rem;
  margin-top: var(--section);
}
.foot-grid h3 { opacity: .55; margin-bottom: 1rem; }
.foot-grid p { max-width: 24rem; opacity: .75; }
.foot-grid li { margin-bottom: .55rem; }
.foot-grid a { text-decoration: none; opacity: .85; background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat; transition: background-size .3s, opacity .3s; }
.foot-grid a:hover { opacity: 1; background-size: 100% 1px; }
.foot-bar { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 1rem; margin-top: 2.5rem; font: var(--micro) var(--mono); letter-spacing: .04em; opacity: .55; }
.foot-bar a { text-decoration: none; }

@media (max-width: 859px) {
  .features { grid-template-columns: 1fr; }
  .feature { min-height: 0; }
  .platforms { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .platforms a { padding: 1.25rem 1.1rem 1.3rem; }
  /* Skills: one card per row, its items in two columns, so the section is not a long ladder */
  .skill-grid { grid-template-columns: 1fr; }
  .skill-grid ul { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 1.5rem; }
  .foot-grid { grid-template-columns: 1fr 1fr; }
  .foot-grid > :first-child { grid-column: 1 / -1; }
}
@media (max-width: 1099px) {
  .examples { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .example, .example:nth-child(-n+2) { grid-column: auto; }
  .quotes { columns: 2; }
}
@media (max-width: 639px) {
  :root { --r-lg: 22px; }
  .examples { grid-template-columns: 1fr; }
  /* Phones: platforms stack, so no name has to break mid-word */
  .platforms { grid-template-columns: 1fr; }
  .platforms span { margin-bottom: 1rem; }
  .quotes { columns: 1; }
  .quotes .quote:nth-child(n+8) { display: none; } /* phones get the lead quote plus seven; the Fiverr link has the rest */
}

/* ---------- Hover states ---------- */
/* Only things you can act on respond to the pointer. Hovers use the individual translate/scale
   properties so they stack with scroll-driven transforms. */
.frame img { transition: scale .6s var(--ease); }
.also a, .fine a { text-decoration: none; background: linear-gradient(currentColor, currentColor) 0 100% / 100% 1px no-repeat; transition: background-size .3s, color .3s; }
.feature, .example, .platforms li { transition: translate .35s var(--ease), box-shadow .35s; }
.tags li { transition: background .25s, color .25s, border-color .25s; }
.rail a::before { transition: transform .3s, opacity .3s, background .3s; }
@media (hover: hover) {
  .example:hover .frame img { scale: 1.04; }
  .also a:hover, .fine a:hover { background-size: 0 1px; background-position: 100% 100%; color: var(--accent-soft); }
  .platforms li:hover, .example:hover { translate: 0 -3px; box-shadow: inset 0 0 0 1px rgba(179,168,255,.45), 0 24px 60px -24px rgba(91,75,255,.6); }
  .platforms li:hover b::after { color: var(--accent-soft); }
  .rail a:hover::before { opacity: 1; transform: scale(1.6); background: var(--accent-soft); }
  .foot-bar a:hover { color: var(--accent-soft); }
}

/* ---------- Native scroll-driven effects for the simpler sections ---------- */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }

  /* Reveals are over by the time a block has fully entered the viewport, so nothing is still
     faded or shifted while it is being read. */
  @supports (animation-timeline: view()) {
    .frame img {
      animation: img-drift linear both; animation-timeline: view(); animation-range: cover 0% cover 100%;
    }
    .feature, .example, .sec-head, .stats, .skill-grid > div, .quote, .platforms li {
      animation: copy-in linear both; animation-timeline: view(); animation-range: entry 0% entry 70%;
    }
    /* Tall blocks finish after a fixed distance instead, so they are not half-faded for a full screen */
    .feature, .example, .quote-lead { animation-range: entry 0% entry 16rem; }
    .platforms li:nth-child(2) { animation-range: entry 10% entry 80%; }
    .platforms li:nth-child(3) { animation-range: entry 20% entry 90%; }
    .platforms li:nth-child(4) { animation-range: entry 30% entry 100%; }
    .ghost { animation: ghost-slide linear both; animation-timeline: view(); }
    .contact h2 {
      animation: big-in linear both; animation-timeline: view(); animation-range: entry 0% cover 35%;
    }
  }
}
@keyframes img-drift { from { transform: scale(1.12) translateY(-3%); } to { transform: scale(1) translateY(0); } }
@keyframes copy-in { from { transform: translateY(2rem); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes big-in { from { transform: translateX(-8%) scale(.9); opacity: .2; } to { transform: none; opacity: 1; } }
@keyframes ghost-slide { from { transform: translateX(22%); } to { transform: translateX(-22%); } }
