:root {
  --bg: #0a0a0a;
  --fg: #ededed;
  --mid: rgba(237, 237, 237, .62);
  --low: rgba(237, 237, 237, .38);
  --line: rgba(237, 237, 237, .12);
  --font: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --pad: clamp(20px, 4vw, 56px);
  --ease: cubic-bezier(.16, 1, .3, 1);
  --dash: rgba(237, 237, 237, .3);
}

*, *::before, *::after { box-sizing: border-box; }
html { background: var(--bg); scroll-behavior: smooth; scroll-padding-top: 72px; -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 400 16px/1.55 var(--font);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
h1, h2, h3, h4, h5, p, ul, ol, dl, dd { margin: 0; }
ol { padding: 0; list-style: none; }
ul { padding: 0; list-style: none; }
a { color: inherit; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
::selection { background: var(--fg); color: var(--bg); }
:focus-visible { outline: 1px solid var(--fg); outline-offset: 6px; }

#grain { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }
main, .footer { position: relative; z-index: 1; }

.skip {
  position: fixed; top: 12px; left: 12px; z-index: 50;
  padding: 8px 12px; background: var(--fg); color: var(--bg);
  font-size: 14px; text-decoration: none;
  transform: translateY(-300%);
}
.skip:focus { transform: none; }

/* ---------- Home ---------- */
.home {
  min-height: 100vh; min-height: 100svh;
  display: flex; align-items: flex-end;
  padding: var(--pad);
}
.home h1 {
  font-family: "Space Grotesk", sans-serif;
  text-shadow: -5px 0 12px rgba(64, 235, 255, .38), 0 0 22px rgba(163, 102, 255, .34), 5px 0 14px rgba(255, 87, 199, .30), 0 0 38px rgba(163, 102, 255, .18);
  font-weight: 400;
  font-size: clamp(29px, 4.6vw, 73px);
  line-height: 1;
  letter-spacing: -.035em;
  margin-left: -.04em;
}
.home__title {
  margin-top: clamp(12px, 1.6vw, 20px);
  font-weight: 300;
  font-size: clamp(17px, 1.75vw, 26px);
  line-height: 1.25;
  letter-spacing: -.012em;
}
.home__pitch {
  margin-top: clamp(14px, 2.2vh, 22px);
  max-width: 50ch;
  font-size: clamp(14.5px, 1.2vw, 17px);
  line-height: 1.5;
  color: var(--mid);
}
.home__focus { margin-top: 4px; font-size: clamp(14.5px, 1.2vw, 17px); line-height: 1.5; letter-spacing: 0; color: var(--mid); }
.home__nav {
  display: flex; flex-wrap: wrap; gap: 6px clamp(22px, 2.6vw, 40px);
  margin-top: clamp(28px, 5vh, 52px);
  font-size: clamp(14px, 1.1vw, 16px);
}
.home__nav a {
  position: relative;
  padding: 6px 0;
  text-decoration: none;
  transition: opacity .35s;
}
.home__nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 2px;
  height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: right;
  transition: transform .5s var(--ease);
}
.home__nav a:hover::after, .home__nav a:focus-visible::after { transform: scaleX(1); transform-origin: left; }
.home__nav:hover a:not(:hover) { opacity: .4; }

/* Hero actions: dark pill with a neon edge that breathes at rest while its
   colors drift slowly round the outline. Hover or keyboard focus brings up
   the full cyan/violet/pink outline and two soft glows that lap that button,
   half a lap apart. With the custom cursor on, the cursor's own orbs do that
   (see Cursor), so the button's glows below stay off. Colors match the dune
   shader's neon(). */
@property --home-spark { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
@property --home-hue { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
.home__actions { gap: 12px 14px; }
.home__actions a {
  display: inline-flex; align-items: center; gap: .55em;
  min-height: 44px; padding: 0 18px;
  border-radius: 10px;
  background: rgba(10, 10, 12, .78);
  box-shadow: 0 0 14px -6px rgba(64, 235, 255, .35);
  color: rgba(237, 237, 237, .9);
  transition: opacity .35s, color .3s, box-shadow .4s ease;
}
.home__actions a::after { content: none; }
.home__ring {
  position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  filter: drop-shadow(0 0 3px rgba(64, 235, 255, .55));
  animation: home-halo 9s ease-in-out infinite alternate;
}
.home__ring::before, .home__ring::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}
.home__ring::before {
  padding: 1px;
  background: conic-gradient(from calc(200deg + var(--home-hue)), #40ebff, #a366ff, #ff57c7, #a366ff, #40ebff);
  opacity: .5;
  animation: home-hue 10s linear infinite, home-breathe 5s ease-in-out infinite alternate;
  transition: opacity .4s ease;
}
.home__ring::after {
  padding: 2px;
  background: repeating-conic-gradient(from var(--home-spark), transparent 0deg 148deg, rgba(64, 235, 255, .45) 160deg, rgba(190, 160, 255, .95) 166deg, rgba(255, 87, 199, .45) 172deg, transparent 180deg);
  opacity: 0;
  transition: opacity .3s ease;
}
@keyframes home-spark { to { --home-spark: 360deg; } }
@keyframes home-hue { to { --home-hue: 360deg; } }
@keyframes home-breathe { from { opacity: .45; } to { opacity: .56; } }
@keyframes home-halo {
  from { filter: drop-shadow(0 0 3px rgba(64, 235, 255, .55)); }
  50% { filter: drop-shadow(0 0 5px rgba(163, 102, 255, .6)); }
  to { filter: drop-shadow(0 0 4px rgba(255, 87, 199, .5)); }
}
/* Lit outline: the colors keep drifting, the breathing stops at full. */
.home__actions a:hover .home__ring::before,
.home__actions a:focus-visible .home__ring::before { animation: home-hue 10s linear infinite; }
.has-cursor .home__ring::after { display: none; }
/* Other button dims only slightly while one is hovered. */
.home__actions:hover a:not(:hover) { opacity: 1; }
@media (hover: hover) {
  .home__actions:hover a:not(:hover) { opacity: .72; }
  .home__actions a:hover {
    color: #fff;
    box-shadow: 0 0 18px -4px rgba(64, 235, 255, .45), 0 0 26px -8px rgba(255, 87, 199, .4);
  }
  .home__actions a:hover .home__ring::before { opacity: 1; }
  .home__actions a:hover .home__ring::after { opacity: 1; animation: home-spark 3.2s linear infinite; }
}
.home__actions a:focus-visible {
  color: #fff;
  box-shadow: 0 0 18px -4px rgba(64, 235, 255, .45), 0 0 26px -8px rgba(255, 87, 199, .4);
}
.home__actions a:focus-visible .home__ring::before { opacity: 1; }
.home__actions a:focus-visible .home__ring::after { opacity: 1; animation: home-spark 3.2s linear infinite; }

/* Name, proposition and links come in once the intro orb has poured into the
   paw and the paw has held, as it starts to spread (script.js adds .is-live off
   the grain's clock, about 3.4s after its first frame, or at once when there is
   no intro to wait for). */
.js .home__id > * { opacity: 0; }
.js.is-live .home__id > * { animation: arrive 1.4s var(--ease) both; }
.js.is-live .home__id > :nth-child(1) { animation-delay: .15s; }
.js.is-live .home__id > :nth-child(2) { animation-delay: .3s; }
.js.is-live .home__id > :nth-child(3) { animation-delay: .45s; }
.js.is-live .home__id > :nth-child(4) { animation-delay: .6s; }
.js.is-live .home__id > :nth-child(5) { animation-delay: .75s; }
@keyframes arrive {
  from { opacity: 0; transform: translateY(14px); filter: blur(8px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

/* ---------- Top bar (appears after the home screen) ---------- */
.bar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 20;
  display: flex; justify-content: space-between; align-items: center;
  padding: 18px var(--pad) 32px;
  font-size: 13px;
  background: linear-gradient(var(--bg) 30%, rgba(10, 10, 10, 0));
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .4s, transform .6s var(--ease), visibility 0s .4s;
}
.bar.is-on { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
.bar nav { display: flex; gap: clamp(16px, 2vw, 28px); }
.bar a { color: var(--low); text-decoration: none; transition: color .25s; }
.bar a:hover, .bar a.is-current, .bar .bar__name { color: var(--fg); }

/* ---------- Sections ---------- */
.section {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: 24px;
  padding: clamp(110px, 20vh, 220px) var(--pad) 0;
}
.section__label {
  grid-column: 1 / span 3;
  position: sticky; top: 72px; align-self: start;
  font-size: clamp(22px, 2.2vw, 32px); font-weight: 300; line-height: 1.1; letter-spacing: -.016em;
  margin-left: -.03em;
  color: var(--fg);
}
.section__body { grid-column: 4 / -1; }

/* ---------- Projects ---------- */
.project { padding: 28px 0 clamp(64px, 11vh, 120px); border-top: 1px solid var(--line); }
.project:last-child { padding-bottom: 0; }
.js .project { transition: opacity .7s; }
.js .project:not(.is-focus):not(:hover) > * { opacity: .42; }
.project > * { transition: opacity .7s; }
.project h3 {
  font-weight: 300;
  font-size: clamp(22px, 3.35vw, 50px);
  line-height: 1.02;
  letter-spacing: -.023em;
  margin-left: -.03em;
  text-wrap: balance;
}
.project__grid {
  display: grid; grid-template-columns: minmax(0, 1fr); column-gap: clamp(32px, 5vw, 80px);
  margin-top: clamp(24px, 4vh, 44px);
}
.project__text p { max-width: 54ch; font-size: clamp(14.5px, 1.12vw, 16px); color: var(--mid); }
.project__text p:first-child { color: var(--fg); }
.project__text p + p { margin-top: 1em; }
.meta { font-size: 13px; }
.meta div { display: grid; grid-template-columns: 6.5em minmax(0, 1fr); column-gap: 16px; padding: 10px 0; border-top: 1px solid var(--line); }
.meta div:last-child { border-bottom: 1px solid var(--line); }
.meta dt { color: var(--low); }
.meta dd { color: var(--mid); }

/* Screenshots. Each .shot grows in proportion to its aspect ratio (--ar), so a
   row of mixed shapes ends up the same height. --sum (the ratios added up)
   caps the row so one or two images never grow taller than about 440px. */
.shots { display: flex; gap: 12px; margin-top: clamp(28px, 5vh, 48px); max-width: calc(var(--sum) * 440px + 24px); }
.shot {
  flex: var(--ar) 1 0; min-width: 0;
  display: block; overflow: hidden; position: relative;
  border: 1px solid var(--line); border-radius: 6px;
  background: #111;
  transition: border-color .3s, box-shadow .4s ease;
}
/* The shot under the pointer or keyboard gets the hero buttons' neon halo.
   box-shadow sits outside the shot, so overflow: hidden still clips the media
   and nothing moves. Hover only where hover is real, so taps do not stick. */
.shot:focus-visible {
  border-color: rgba(163, 102, 255, .7); z-index: 1;
  box-shadow: 0 0 20px -4px rgba(64, 235, 255, .55), 0 0 28px -8px rgba(255, 87, 199, .5);
}
@media (hover: hover) {
  .shot:hover {
    border-color: rgba(163, 102, 255, .7); z-index: 1;
    box-shadow: 0 0 20px -4px rgba(64, 235, 255, .55), 0 0 28px -8px rgba(255, 87, 199, .5);
  }
}
.shot img { display: block; width: 100%; height: auto; transition: filter .7s; }
/* Colour only on the project you are looking at; the rest stay monochrome. */
.js .project:not(.is-focus):not(:hover) .shot img,
.js .project:not(.is-focus):not(:hover) .shot video { filter: grayscale(1); }
/* A shot that opens a video carries a small play mark in its corner. */
.shot--video { position: relative; }
.shot--video::after {
  content: ""; position: absolute; right: 10px; bottom: 10px;
  width: 26px; height: 26px; border-radius: 50%;
  background: rgba(10, 10, 10, .72) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 26'%3E%3Cpath d='M10.5 8.5v9l7-4.5z' fill='%23fff'/%3E%3C/svg%3E") center / contain no-repeat;
  border: 1px solid var(--line);
}
/* The clip lies over its still image and only shows once it is playing. */
.shot video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; pointer-events: none;
  opacity: 0; transition: opacity .3s, filter .7s;
}
.shot.is-playing video { opacity: 1; }

/* Product demo. A full-width 16:9 player with its own native controls. */
.demo { margin: clamp(28px, 5vh, 48px) 0 0; }
.demo video {
  display: block; width: 100%; height: auto; aspect-ratio: 16 / 9;
  border: 1px solid var(--line); border-radius: 6px;
  background: #111;
  transition: filter .7s;
}
.js .project:not(.is-focus):not(:hover) .demo video { filter: grayscale(1); }
.demo figcaption { margin-top: 14px; max-width: 70ch; font-size: 13px; color: var(--mid); }
.demo__meta { color: var(--mid); margin-right: .5em; }
/* Portrait recording (Sidetone, 1000x1120): kept to a readable width and left
   aligned; on narrow screens it fills the column. */
.demo--portrait video { aspect-ratio: 1000 / 1120; max-width: 560px; }

/* Full-size view. Shown at true size and scrolls if the screenshot is tall. */
.lightbox {
  position: fixed; inset: 0; z-index: 80;
  overflow: auto; overscroll-behavior: contain;
  padding: 5vh 4vw;
  background: rgba(10, 10, 10, .95);
  opacity: 0; visibility: hidden;
  transition: opacity .3s, visibility 0s .3s;
}
.lightbox.is-open { opacity: 1; visibility: visible; transition-delay: 0s; }
.lightbox img, .lightbox video { display: block; margin: 0 auto; max-width: 100%; height: auto; border: 1px solid var(--line); border-radius: 6px; }
.lightbox video { max-height: 90vh; background: #111; }
.lightbox [hidden] { display: none; }
.lightbox p { margin: 14px auto 0; max-width: 70ch; text-align: center; font-size: 13px; color: var(--low); }
.is-locked { overflow: hidden; }

/* ---------- Case studies ---------- */
/* A closed <details> under the screenshots. The summary is the only extra
   thing a skimming reader sees; the full write-up opens in place. */
.case { margin-top: clamp(28px, 5vh, 44px); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.case > summary {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px;
  padding: 16px 0;
  list-style: none; cursor: pointer;
}
.case > summary::-webkit-details-marker { display: none; }
.case__toggle { position: relative; flex: none; align-self: center; width: 11px; height: 11px; }
.case__toggle::before, .case__toggle::after {
  content: ""; position: absolute; left: 0; right: 0; top: 5px;
  height: 1px; background: currentColor;
  transition: transform .5s var(--ease);
}
.case__toggle::after { transform: rotate(90deg); }
details[open] > summary .case__toggle::after { transform: rotate(0); }
.case__title { font-size: 15px; }
.case__hint { font-size: 13px; color: var(--low); transition: color .25s; }
summary:hover .case__hint { color: var(--mid); }

.case__body { padding-bottom: 12px; }
.case__part {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 7fr); column-gap: 24px;
  padding: 20px 0 26px; border-top: 1px solid var(--line);
}
.case__part h4 { font-size: 13px; font-weight: 400; color: var(--low); }
.case__part p { max-width: 62ch; font-size: 14.5px; color: var(--mid); }
.case__part p + p { margin-top: .9em; }
.case__part p:first-child:not(.case__source) { color: var(--fg); }
.case__source { margin-bottom: 14px; font-size: 12.5px; color: var(--low); }
.flow + .case__source { margin: 18px 0 0; }

.points li { position: relative; max-width: 62ch; padding-left: 18px; font-size: 14.5px; color: var(--mid); }
.points li + li { margin-top: 12px; }
.points li::before { content: "–"; position: absolute; left: 0; color: var(--low); }
.points strong { font-weight: 400; color: var(--fg); }
.case__tradeoff { margin-top: 22px; padding-left: 16px; border-left: 1px solid var(--line); }
.case__tradeoff span { display: block; margin-bottom: 4px; font-size: 12px; color: var(--low); }

/* Verdict key, drawn in the site's monochrome rather than the app's colours. */
.legend { margin-bottom: 22px; font-size: 13.5px; }
.legend div { display: grid; grid-template-columns: 9em minmax(0, 1fr); column-gap: 16px; padding: 8px 0; border-top: 1px solid var(--line); }
.legend div:last-child { border-bottom: 1px solid var(--line); }
.legend dt { display: flex; align-items: center; gap: 10px; }
.legend dd { color: var(--mid); }
.swatch { flex: none; width: 10px; height: 10px; border: 1px solid var(--fg); }
.swatch--hold { background: var(--fg); }
.swatch--review { background: linear-gradient(90deg, var(--fg) 50%, transparent 50%); }
.swatch--unreadable { border: 1px dashed var(--mid); }

/* Workflow diagram: steps read top to bottom along a thin spine. */
.flow li {
  position: relative;
  display: grid; grid-template-columns: 7em minmax(0, 1fr); column-gap: 16px;
  padding: 0 0 20px 26px;
  font-size: 13px;
}
.flow li:last-child { padding-bottom: 0; }
.flow li::before { content: ""; position: absolute; left: 4px; top: 0; bottom: 0; width: 1px; background: var(--line); }
.flow li:first-child::before { top: 16px; }
.flow li:last-child::before { bottom: auto; height: 16px; }
.flow li::after {
  content: ""; position: absolute; left: 0; top: 12px;
  width: 9px; height: 9px; border-radius: 50%;
  border: 1px solid var(--mid); background: var(--bg);
}
/* A small arrowhead on the spine, just above the next step. */
.flow li:not(:last-child) .flow__kind::after {
  content: ""; position: absolute; left: 1px; bottom: 3px;
  border: 4px solid transparent; border-bottom: 0; border-top: 5px solid var(--low);
}
.flow__kind { padding-top: 8px; color: var(--low); }
.flow__nodes { display: flex; flex-wrap: wrap; gap: 8px; }
.node {
  display: inline-block; max-width: 56ch;
  padding: 7px 12px;
  border: 1px solid var(--line); border-radius: 4px;
  line-height: 1.45; color: var(--fg);
}
.node small { margin-left: 6px; font-size: 11.5px; color: var(--low); }
.node--dashed, .node--person { border-style: dashed; border-color: var(--dash); }
.node--person { color: var(--mid); }

.case__close { padding: 10px 0 4px; font-size: 13px; color: var(--low); transition: color .25s; }
.case__close:hover { color: var(--fg); }

/* ---------- About ---------- */
.story, .lead { max-width: 62ch; font-size: clamp(16px, 1.5vw, 20.5px); line-height: 1.45; letter-spacing: -.01em; color: var(--mid); }
.lead { color: var(--fg); }
.story p + p { margin-top: 1.1em; }
.story .story__key { color: var(--fg); }
.facts { margin-top: clamp(64px, 11vh, 120px); }

/* ---------- How I work ---------- */
.steps {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 32px 24px;
  margin-top: clamp(40px, 7vh, 72px);
}
.steps li { padding-top: 16px; border-top: 1px solid var(--line); }
/* Step numbers pick up the dune/name colors: the gradient fills the digits and
   drop-shadow carries the glow, since text-shadow paints over clipped text. */
.steps__n {
  display: block; width: fit-content; margin-bottom: 14px;
  font-size: clamp(28px, 2.6vw, 36px); line-height: 1; letter-spacing: .02em;
  color: #a366ff;
  background: linear-gradient(100deg, #40ebff 0%, #a366ff 55%, #ff57c7 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 0 6px rgba(64, 235, 255, .35)) drop-shadow(0 0 14px rgba(163, 102, 255, .3));
}
.steps strong { display: block; font-weight: 400; font-size: 15px; }
.steps p { margin-top: 8px; max-width: 34ch; font-size: 13.5px; color: var(--mid); }
.ai-note {
  margin-top: clamp(40px, 7vh, 64px); max-width: 62ch;
  padding-left: 16px; border-left: 1px solid var(--line);
  font-size: 14.5px; color: var(--mid);
}
.ai-note span { display: block; margin-bottom: 6px; font-size: 12px; color: var(--low); }

.group { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 7fr); column-gap: 24px; padding: 20px 0 8px; border-top: 1px solid var(--line); }
.group h3 { font-size: 13px; font-weight: 400; color: var(--low); }
.group li { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 24px; padding-bottom: 14px; }
.group strong { font-weight: 400; font-size: 14.5px; }
.group span { grid-column: 1; font-size: 13px; color: var(--low); }
.group em { grid-column: 2; grid-row: 1; font-style: normal; font-size: 13px; color: var(--low); }

/* ---------- Contact ---------- */
.section--contact { padding-bottom: clamp(110px, 20vh, 220px); }
.email {
  display: block; max-width: 100%;
  font-weight: 300;
  font-size: clamp(18px, 3.8vw, 59px);
  line-height: 1.05;
  letter-spacing: -.026em;
  margin-left: -.03em;
  text-align: left;
  overflow-wrap: anywhere;
}
.contact__note { margin-top: clamp(20px, 3vh, 32px); max-width: 44ch; font-size: 14.5px; color: var(--mid); }
.contact__note--low { margin-top: 8px; font-size: 13px; color: var(--low); }
.contact__note a { text-underline-offset: 3px; text-decoration-thickness: 1px; transition: color .25s; }
.contact__note a:hover { color: var(--fg); }
.contact__links { display: flex; flex-wrap: wrap; gap: 10px 28px; margin-top: clamp(28px, 4vh, 40px); font-size: 14.5px; }
.contact__links a { text-decoration: none; border-bottom: 1px solid var(--line); padding-bottom: 2px; transition: border-color .25s; }
.contact__links a:hover { border-color: var(--fg); }

/* ---------- Footer ---------- */
.footer {
  display: flex; justify-content: space-between; align-items: center;
  padding: 20px var(--pad) 24px;
  border-top: 1px solid var(--line);
  font-size: 13px; color: var(--low);
}
.footer a { text-decoration: none; transition: color .25s; }
.footer a:hover { color: var(--fg); }
.footer__paw { width: 14px; height: 14px; opacity: .22; transition: opacity .3s, transform .5s var(--ease); }
.footer__paw svg { display: block; width: 100%; height: 100%; fill: var(--fg); }
.footer__paw:hover, .footer__paw:focus-visible { opacity: 1; transform: rotate(-12deg) scale(1.25); }

/* ---------- Toast ---------- */
.toast {
  position: fixed; left: 50%; bottom: 28px; z-index: 60;
  padding: 7px 14px;
  font-size: 13px;
  border: 1px solid var(--line); border-radius: 999px;
  background: rgba(10, 10, 10, .82);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  transform: translate(-50%, 10px); opacity: 0; pointer-events: none;
  transition: transform .5s var(--ease), opacity .3s;
}
.toast.is-on { transform: translate(-50%, 0); opacity: 1; }

/* ---------- Cursor ---------- */
/* A dot marks exactly where the pointer is. A faint neon ring trails it with
   two glowing orbs circling on opposite sides, and over anything clickable,
   or anything focused from the keyboard, the same ring and orbs wrap that
   element's outline. script.js sizes the ring and moves the orbs. */
.cursor { display: none; }
.has-cursor, .has-cursor * { cursor: none !important; }
/* Video players keep the system pointer for their own controls. */
.has-cursor video[controls] { cursor: auto !important; }
.has-cursor .cursor {
  display: block; position: fixed; left: 0; top: 0; z-index: 100;
  pointer-events: none; opacity: 0;
}
.has-cursor.cursor-on .cursor--dot, .has-cursor.cursor-ring-on .cursor--ring { opacity: 1; }
.has-cursor.cursor-native .cursor { opacity: 0; }
.has-cursor.cursor-locked .cursor--dot { opacity: 0; }
.cursor--dot {
  width: 5px; height: 5px; margin: -2.5px 0 0 -2.5px; border-radius: 50%;
  background: #fff; mix-blend-mode: difference;
  transition: opacity .3s;
}
.cursor--ring {
  width: 0; height: 0;
  filter: drop-shadow(0 0 3px rgba(64, 235, 255, .55));
  transition: opacity .3s;
}
.cursor__svg { position: absolute; left: 0; top: 0; display: block; overflow: visible; fill: none; }
.cursor__edge { stroke: url(#cursorEdge); stroke-width: 1; opacity: .45; transition: opacity .3s; }
.cursor-locked .cursor__edge { opacity: .9; }
/* Two small glowing orbs ride the outline half a lap apart. Each is one
   radial blend, a white core through cyan and violet out to a faint pink
   halo, so there is no hard edge or color band. */
.cursor__orb { fill: url(#cursorOrb); }
/* The ring stands in for the focus outline of the element it wraps. */
.has-cursor.cursor-ring-on .is-cursor-target:focus-visible { outline-color: transparent; }
.cursor--label { margin: 30px 0 0 30px; font-size: 12px; color: var(--fg); white-space: nowrap; transition: opacity .25s; }
.has-cursor.cursor-on.cursor-labelled .cursor--label { opacity: 1; }

/* ---------- Scroll reveal ---------- */
.js [data-reveal] { opacity: 0; transform: translateY(18px); transition: opacity 1.1s var(--ease), transform 1.1s var(--ease); }
.js [data-reveal].is-seen { opacity: 1; transform: none; }

/* ---------- Small screens ---------- */
@media (max-width: 1180px) {
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 860px) {
  .section { display: block; }
  .section__label { position: static; margin-bottom: 28px; }
  .project__grid { grid-template-columns: 1fr; row-gap: 28px; }
  /* Phones: a sideways-scrolling strip, all the same height. */
  .shots { max-width: none; overflow-x: auto; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  /* The strip scrolls, so it would clip the halo. 20px of padding gives the
     halo room and the matching negative margin keeps every shot in place. */
  .shots { padding: 20px; margin: calc(clamp(28px, 5vh, 48px) - 20px) -20px -20px; scroll-padding-inline: 20px; }
  .shots::-webkit-scrollbar { display: none; }
  .shot { flex: 0 0 auto; height: 300px; width: calc(300px * var(--ar)); scroll-snap-align: start; }
  .shot img { width: 100%; height: 100%; }
  .group { grid-template-columns: 1fr; row-gap: 12px; }
  .case__part { grid-template-columns: 1fr; row-gap: 14px; }
}
@media (max-width: 480px) {
  .steps { grid-template-columns: 1fr; }
  .flow li { grid-template-columns: 1fr; row-gap: 6px; }
  .flow__kind { padding-top: 6px; }
  .legend div { grid-template-columns: 1fr; row-gap: 2px; }
  .group li { grid-template-columns: 1fr; }
  .group em { grid-column: 1; grid-row: auto; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-delay: 0s !important; transition-duration: .01ms !important; }
  /* The glows stay parked on the lit outline instead of circling. */
  .home__actions a .home__ring::after { animation: none !important; --home-spark: 300deg; }
  .home__ring, .home__ring::before { animation: none !important; }
}
