/* ============================================================
   Krishna Ganga — portfolio
   1. tokens      2. base       3. scroll progress
   4. nav         5. hero       6. marquee
   7. work        8. stack      9. about/stats
   10. footer     11. reveal    12. motion utilities
   ============================================================ */

/* ---------- 1. tokens ---------- */
:root {
  --paper: #f7f0dd;
  --paper-2: #f0e6cd;
  --ink: #1a1712;
  --soft: #736b5c;
  --line: rgba(26, 23, 18, .17);
  --card: #e7dcc0;

  --coral: #d95d3f;
  --blue: #3f70d4;
  --green: #327b59;

  --serif: "Playfair Display", Georgia, serif;
  /* The hero name is the one place both themes share a face: light remaps
     --serif to its display serif, and the bust composition was drawn around
     Playfair's proportions. */
  --serif-hero: "Playfair Display", Georgia, serif;
  --vogue: "Bodoni Moda", "Didot", "Playfair Display", Georgia, serif;
  /* Light theme display face. Lumaire is commercial and self-hosted; until
     its files are in assets/fonts this falls back to Instrument Serif.
     To try another, change the second name here and the family in the
     Google Fonts link in index.html. */
  --display: "Lumaire", "Instrument Serif", "Bodoni Moda", Georgia, serif;
  --sans: "DM Sans", Arial, sans-serif;
  --mono: "DM Mono", monospace;

  --ease: cubic-bezier(.2, .8, .2, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --gutter: 5.2vw;
}

html.dark {
  --paper: #14120e;
  --paper-2: #1d1a14;
  --ink: #f6f0e0;
  --soft: #a9a191;
  --line: rgba(246, 240, 224, .16);
  --card: #262218;

  --coral: #ff9a76;
  --blue: #8eafff;
  --green: #7dcc9e;
}

/* Drop licensed Lumaire files into assets/fonts and uncomment to use them.
@font-face {
  font-family: "Lumaire";
  src: url("assets/fonts/lumaire.woff2") format("woff2"),
       url("assets/fonts/lumaire.woff") format("woff");
  font-weight: 400;
  font-display: swap;
}
*/

/* ---------- 2. base ---------- */
* { box-sizing: border-box; }

/* Author rules that set a display value silently beat the [hidden] attribute's
   UA display:none. Several elements here are toggled with .hidden and are also
   given display:block/flex, so hidden must win explicitly. */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; scrollbar-gutter: stable; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  overflow-x: hidden;
  transition: background .45s var(--ease), color .45s var(--ease);
}

body.reveal-open { overflow: hidden; }

/* A little tooth on the paper. Sits above the content but below the nav and
   the modal, and never intercepts a pointer. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 60;
  pointer-events: none;
  opacity: .19;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}

.dark body::after { opacity: .07; }

a { color: inherit; text-decoration: none; }

::selection { background: var(--coral); color: var(--paper); }

.eyebrow {
  margin: 0;
  font: 10px/1.4 var(--mono);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--soft);
}

.eyebrow b { font-weight: 400; color: var(--coral); }

.tint-coral { color: var(--coral); }
.tint-blue  { color: var(--blue); }
.tint-green { color: var(--green); }

.text-coral { color: var(--coral); }
.text-blue  { color: var(--blue); }
.text-green { color: var(--green); }

.hero__lede span[class^="text-"],
.work-intro span[class^="text-"] { font-weight: 500; }

/* ---------- 3. loading screen ---------- */
.loader {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 30px;
  background: var(--paper);
  transition: opacity .7s var(--ease), visibility .7s;
}

.loader.is-done { opacity: 0; visibility: hidden; }

.loader__mark {
  font: 400 clamp(64px, 12vw, 130px)/1 var(--vogue);
  letter-spacing: .16em;
  padding-left: .16em;
  color: var(--ink);
  opacity: 0;
  animation: markIn 1s var(--ease-out) forwards;
}

@keyframes markIn {
  from { opacity: 0; transform: translateY(14px); letter-spacing: .34em; }
  to   { opacity: 1; transform: none; letter-spacing: .16em; }
}

.loader__bar {
  width: min(240px, 52vw);
  height: 1px;
  background: var(--line);
  overflow: hidden;
}

.loader__bar span {
  display: block;
  width: 0;
  height: 100%;
  background: var(--coral);
}

.loader__count {
  font: 10px var(--mono);
  letter-spacing: .18em;
  color: var(--soft);
}

/* Nothing behind the loader should animate in until it lifts. */
.is-loading { overflow: hidden; }

/* ---------- 3b. scroll progress ---------- */
.progress {
  position: fixed;
  inset: 0 auto auto 0;
  z-index: 90;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  background: linear-gradient(90deg, var(--coral), var(--blue), var(--green));
}

/* ---------- 4. nav ---------- */
.nav {
  position: fixed;
  inset: 0 0 auto;
  z-index: 80;
  display: grid;
  /* The links sit midway between the brand and the toggle, not midway across
     the viewport: the two flanks are different widths, so centring on the
     page leaves the links visibly closer to the wider one. */
  grid-template-columns: auto 1fr auto;
  align-items: center;
  padding: 22px var(--gutter);
  border-bottom: 1px solid transparent;
  transition: transform .45s var(--ease), background .35s, border-color .35s;
}

.nav.is-scrolled {
  background: color-mix(in srgb, var(--paper) 94%, transparent);
  border-color: var(--line);
}

.nav.is-hidden { transform: translateY(-104%); }

.nav__brand {
  font: 400 25px/1 var(--vogue);
  letter-spacing: .12em;
  padding-left: .12em;
}
.nav__brand span { color: var(--coral); }

.nav__links {
  justify-self: center;
  display: flex;
  gap: 28px;
  font: 11px/1 var(--mono);
  letter-spacing: .08em;
  text-transform: uppercase;
}

.nav__links a {
  position: relative;
  padding: 8px 0;
}

.nav__links a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .4s var(--ease);
}

.nav__links a:hover::after { transform: scaleX(1); transform-origin: left; }

.nav__end {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 16px;
}

/* Two rules that become an X. Hidden until the links leave the bar. */
.nav__burger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 34px;
  height: 34px;
  margin-right: -6px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}

.nav__burger span {
  display: block;
  width: 22px;
  height: 1px;
  margin-left: auto;
  background: var(--ink);
  transition: transform .4s var(--ease), width .4s var(--ease), opacity .3s;
}

.nav__burger span:last-child { width: 14px; }

.nav__burger[aria-expanded="true"] span:first-child { transform: translateY(3px) rotate(45deg); }
.nav__burger[aria-expanded="true"] span:last-child { width: 22px; transform: translateY(-3px) rotate(-45deg); }

/* ---- phone menu ---- */
.menu {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 8vh;
  padding: 120px var(--gutter) 44px;
  background: var(--paper);
  opacity: 0;
  /* Not display alone: it has to stop taking clicks while it is invisible. */
  visibility: hidden;
  pointer-events: none;
  /* visibility is a discrete property: without the explicit delays it would
     flip halfway through the fade, which is also too late to take focus. */
  transition: opacity .4s var(--ease), visibility 0s .4s;
}

.menu.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity .4s var(--ease), visibility 0s;
}

.menu__links {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.menu__links a {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding: 6px 0;
  font: 500 clamp(38px, 12vw, 62px)/1.05 var(--serif-hero);
  letter-spacing: -.045em;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .5s var(--ease-out), transform .6s var(--ease-out);
}

.menu__links a i {
  font: 10px var(--mono);
  font-style: normal;
  letter-spacing: .16em;
  color: var(--soft);
}

.menu.is-open .menu__links a { opacity: 1; transform: none; }
.menu.is-open .menu__links a:nth-child(2) { transition-delay: .05s; }
.menu.is-open .menu__links a:nth-child(3) { transition-delay: .1s; }
.menu.is-open .menu__links a:nth-child(4) { transition-delay: .15s; }
.menu.is-open .menu__links a:nth-child(5) { transition-delay: .2s; }

.menu__foot {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-top: 26px;
  border-top: 1px solid var(--line);
  font: 12px var(--mono);
  letter-spacing: .06em;
  color: var(--soft);
  opacity: 0;
  transition: opacity .5s var(--ease-out) .24s;
}

.menu.is-open .menu__foot { opacity: 1; }
.menu__foot a { align-self: start; }

/* The bar stays above the panel so the close control is always reachable. */
.menu-open .nav { z-index: 90; }
.menu-open, .menu-open body { overflow: hidden; }

.theme-toggle {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: 11px/1 var(--mono);
  letter-spacing: .08em;
  text-transform: uppercase;
  cursor: pointer;
}

.theme-toggle span {
  width: 13px;
  height: 13px;
  border: 1px solid currentColor;
  border-radius: 50%;
  background: linear-gradient(90deg, currentColor 50%, transparent 50%);
  transition: transform .5s var(--ease);
}

.theme-toggle:hover span { transform: rotate(180deg); }

/* ---------- 5. hero ---------- */
.hero {
  position: relative;
  min-height: 100svh;
  padding: clamp(90px, 12vh, 130px) var(--gutter) 34px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: min(4vh, 40px);
  overflow: hidden;
}

.hero > *:not(.hero__system) { position: relative; z-index: 1; }

.hero__system { position: absolute; inset: 0 0 24% 12%; pointer-events: none; }
/* The field occupies the upper right only — it can then never compete with
   the name on the left or the work index below it. The mask softens the two
   edges that meet content. */
/* The bust sits in the right half of the hero, opposite the type. It fades
   in only once the model is actually on screen, so a slow load or a failed
   one simply leaves the hero as it was. */
.hero__model {
  position: absolute;
  /* stops above the foot band: at full height the bust sat on top of the
     work index in the lower right */
  inset: 0 0 46% auto;
  width: min(52%, 620px);
  opacity: 0;
  transition: opacity 1.1s var(--ease);
  pointer-events: none;
}

.has-model .hero__model { opacity: 1; }

/* Dark treatment: the name stands full height behind the bust and he
   occludes it. A second copy of the name sits above him, clipped to its
   lower part, so the letters read behind at the top and in front at the
   bottom. The depth comes from the composition, not from motion. */
.has-model .hero__system { inset: 0; z-index: 1; }

.has-model .hero__model {
  inset: 0 0 20% 0;
  width: 100%;
  /* takes the pointer so hovering him can bring the light up; it stops
     above the foot band, so nothing there stops being clickable */
  pointer-events: auto;
}

.has-model .hero__name,
.has-model .hero__name-echo {
  position: absolute;
  inset: 0 0 26% 0;
  z-index: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 0;
  pointer-events: none;
  font: 500 clamp(64px, min(15vw, 21vh), 230px)/.82 var(--serif-hero);
  letter-spacing: -.05em;
  text-align: center;
  color: var(--ink);
}

.has-model .hero__name-echo {
  z-index: 2;
}

/* Each word appears once: Krishna behind him, Ganga in front. The other
   half of each copy is held in place so the two stay registered, but not
   drawn. */
.has-model .hero__name .line:nth-child(2) { opacity: 0; }
.has-model .hero__name-echo span:first-child { opacity: 0; }

.has-model .hero__name .line,
.has-model .hero__name-echo span {
  display: block;
  overflow: visible;
  line-height: .82;
  margin: 0;
}

.has-model .hero__name .line > span { transform: none; }

.has-model .hero__name em,
.has-model .hero__name-echo em { font-style: italic; font-weight: 500; }

/* Ganga carries the accent, so the two words read as two things rather
   than one long line broken in half. */
.has-model .hero__name-echo em { color: var(--coral); }

/* the name carries the hero now, so the flat field stays out of it */
.has-model .hero__canvas { display: none; }

.hero__name-echo { display: none; }

.hero__canvas {
  position: absolute;
  inset: 0;
  /* canvas is a replaced element: it needs explicit sizing to fill the
     inset box, "auto" would collapse it to its intrinsic dimensions */
  width: 100%;
  height: 100%;
  -webkit-mask-image: linear-gradient(102deg, transparent 2%, #000 40%),
                      linear-gradient(#000 52%, transparent 98%);
  mask-image: linear-gradient(102deg, transparent 2%, #000 40%),
              linear-gradient(#000 52%, transparent 98%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

.hero__coordinate {
  position: absolute;
  right: var(--gutter);
  bottom: 38px;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font: 10px var(--mono);
  letter-spacing: .14em;
  color: var(--soft);
  opacity: .7;
}

.hero__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
}

.hero__status {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 9px;
  font: 10px var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--soft);
}

.dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 60%, transparent);
  animation: ping 2.4s ease-out infinite;
}

@keyframes ping {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 55%, transparent); }
  70%  { box-shadow: 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

.hero__name {
  margin: 0;
  /* Bounded by viewport height too, so the name never pushes the work
     index below the fold on a short laptop screen. */
  font: 600 clamp(64px, min(12.6vw, 16.5vh), 196px)/.72 var(--serif);
  letter-spacing: -.09em;
}
.hero__name em { font-weight: 500; letter-spacing: -.1em; }

/* mask-reveal lines
   line-height stays generous inside the mask so Playfair's ascenders and
   descenders are not clipped; the tight optical stack comes from the
   negative margin between lines instead. */
.line { display: block; overflow: hidden; line-height: 1.08; }
.line + .line { margin-top: -.36em; }
.line > span {
  display: block;
  transform: translateY(110%);
  transition: transform 1.1s var(--ease-out);
}
.is-ready .line > span { transform: translateY(0); }
.is-ready .line:nth-child(2) > span { transition-delay: .1s; }



/* ---- hero foot: pitch on the left, the actual work on the right ---- */
.hero__foot {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 400px);
  align-items: end;
  gap: 6vw;
}

.hero__lede {
  max-width: 25ch;
  margin: 0;
  font-size: clamp(18px, 1.9vw, 26px);
  line-height: 1.25;
  letter-spacing: -.04em;
}

.hero__meta {
  margin: 16px 0 0;
  font: 10px var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--soft);
}

.hero__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 22px; }

.round-link {
  display: inline-flex;
  align-items: center;
  gap: 18px;
  position: relative;
  isolation: isolate;
  border: 1px solid var(--ink);
  border-radius: 100px;
  padding: 15px 20px 15px 24px;
  overflow: hidden;
  font: 11px var(--mono);
  letter-spacing: .06em;
  text-transform: uppercase;
  transition: color .3s var(--ease), border-color .3s;
}

.round-link::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  background: var(--ink);
  transform: translateY(101%);
  transition: transform .5s var(--ease);
}

.round-link:hover { color: var(--paper); }
.round-link:hover::before { transform: translateY(0); }
.round-link span { font-size: 16px; transition: transform .4s var(--ease); }
.round-link:hover span { transform: translateY(3px); }

.round-link--ghost { border-color: var(--line); color: var(--soft); }
.round-link--ghost:hover { color: var(--paper); border-color: var(--ink); }
.round-link--ghost:hover span { transform: translate(3px, -3px); }

/* ---- above-the-fold work index ---- */
.hero__now-label {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 14px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--soft);
}

.hero__now-label span {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 60%, transparent);
  animation: nowPulse 2.4s ease-out infinite;
}

@keyframes nowPulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 55%, transparent); }
  70%  { box-shadow: 0 0 0 7px color-mix(in srgb, var(--green) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 0%, transparent); }
}

.hero__index {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line);
}

.hero__index button {
  position: relative;
  width: 100%;
  display: grid;
  grid-template-columns: 30px 1fr auto 16px;
  align-items: baseline;
  gap: 14px;
  padding: 13px 0;
  border: 0;
  border-bottom: 1px solid var(--line);
  background: transparent;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

/* the fill that wipes in from the left on hover */
.hero__index button::before {
  content: "";
  position: absolute;
  inset: 0 -14px;
  z-index: -1;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .5s var(--ease);
}

.hero__index button:hover::before,
.hero__index button:focus-visible::before { transform: scaleX(1); }

.hero__index i,
.hero__index em,
.hero__index u {
  font: 10px var(--mono);
  font-style: normal;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--soft);
  text-decoration: none;
  transition: color .35s var(--ease), transform .45s var(--ease);
}

.hero__index b {
  font: 500 clamp(22px, 2.2vw, 30px)/1 var(--serif);
  letter-spacing: -.045em;
  transition: color .35s var(--ease), transform .45s var(--ease);
}

.hero__index button:hover b,
.hero__index button:focus-visible b { color: var(--paper); transform: translateX(6px); }

.hero__index button:hover i,
.hero__index button:hover em,
.hero__index button:hover u,
.hero__index button:focus-visible i,
.hero__index button:focus-visible em,
.hero__index button:focus-visible u { color: color-mix(in srgb, var(--paper) 72%, transparent); }

.hero__index button:hover u { transform: translate(3px, -3px); }

/* floating thumbnail that follows the pointer across the index */
.peek {
  position: fixed;
  z-index: 70;
  left: 0;
  top: 0;
  width: 230px;
  height: 290px;
  margin: -145px 0 0 -115px;
  background: var(--card) center/cover;
  border-radius: 3px;
  box-shadow: 0 30px 60px rgba(0, 0, 0, .28);
  opacity: 0;
  transform: scale(.9) rotate(-4deg);
  pointer-events: none;
  transition: opacity .35s var(--ease), transform .55s var(--ease);
}

.peek.is-visible { opacity: 1; transform: scale(1) rotate(-2deg); }

/* ---------- 6. marquee ---------- */
.marquee {
  display: flex;
  padding: 22px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  overflow: hidden;
  user-select: none;
}

/* Runs as a compositor animation, not from script. A JS-driven transform is
   main-thread work, so anything that busies the main thread, scrolling most of
   all, stutters it. This keeps turning at a constant speed regardless of what
   the page is doing, and does not pause on hover. */
.marquee__track {
  display: flex;
  flex-shrink: 0;
  gap: 42px;
  padding-right: 42px;
  align-items: center;
  will-change: transform;
  animation: marquee-slide 38s linear infinite;
}

@keyframes marquee-slide {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-100%, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none; }
}

.marquee__track span {
  font: 500 clamp(26px, 3.6vw, 52px)/1 var(--serif);
  letter-spacing: -.05em;
  white-space: nowrap;
}
.marquee__track i {
  font-style: normal;
  font-size: 14px;
  color: var(--coral);
}

/* ---------- 7. work ---------- */
.work { padding: 8vw var(--gutter) 9vw; }

.section-head h2 {
  margin: 18px 0 0;
  font: 500 clamp(58px, 8vw, 130px)/.78 var(--serif);
  letter-spacing: -.08em;
}

.work-intro {
  max-width: 580px;
  margin: 64px 0 58px;
  font-size: clamp(18px, 2vw, 27px);
  line-height: 1.25;
  letter-spacing: -.04em;
}

.deck__hint {
  margin: 0 0 26px;
  font: 10px var(--mono);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--soft);
}

/* The deck: cards overlap in a fan and spread apart on hover. Sized by
   aspect ratio so the shatter tiles map cleanly onto the card art. */
.deck {
  position: relative;
  height: clamp(400px, 46vw, 560px);
  display: flex;
  align-items: center;
  justify-content: center;
  perspective: 1400px;
}

.project {
  position: absolute;
  width: clamp(240px, 25vw, 320px);
  height: clamp(360px, 41vw, 500px);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--card);
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  transform-origin: bottom center;
  box-shadow: 0 18px 40px rgba(40, 28, 8, .14);
  transition: transform .65s var(--ease), box-shadow .5s, border-color .4s, color .4s;
}

/* fanned resting positions */
.project--rice     { transform: translateX(-52%) rotate(-9deg); z-index: 1; }
.project--moksh    { transform: translateY(-10px); z-index: 3; }
.project--mecha { transform: translateX(52%) rotate(9deg); z-index: 2; }

.project:hover {
  z-index: 6;
  color: #fff;
  border-color: transparent;
  box-shadow: 0 34px 70px rgba(40, 28, 8, .34);
}

/* Hover changes no geometry: the cards hold their fan positions and the
   hover state is carried entirely by the artwork, colour and depth. */

.project--rice     { background: color-mix(in srgb, #74a96b 15%, var(--card)); }
.project--moksh    { background: color-mix(in srgb, #d69b42 15%, var(--card)); }
.project--mecha { background: color-mix(in srgb, #5f83cf 15%, var(--card)); }

.project::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  background: linear-gradient(180deg, rgba(10, 10, 10, .22), rgba(10, 10, 10, .82)), var(--image) center/cover;
  opacity: 0;
  transition: opacity .5s var(--ease);
}

.project:hover::before { opacity: 1; }

/* a card that is being shattered must not linger under the pieces */
.project.is-shattering { opacity: 0; transition: opacity .06s; }

.project__top,
.project__bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font: 9px var(--mono);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--soft);
  transition: color .4s;
}

.project:hover .project__top,
.project:hover .project__bottom { color: rgba(255, 255, 255, .8); }

.project__title {
  position: relative;
  z-index: 2;
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.project__title em {
  font: 500 clamp(34px, 3.4vw, 46px)/.92 var(--serif);
  letter-spacing: -.055em;
  transition: color .4s;
}

.project--rice     .project__title em { color: #34702f; }
.project--moksh    .project__title em { color: #945d17; }
.project--mecha .project__title em { color: #33569f; }

.dark .project--rice     .project__title em { color: #a8e69b; }
.dark .project--moksh    .project__title em { color: #f2c26e; }
.dark .project--mecha .project__title em { color: #9cb9ff; }

.project:hover .project__title em { color: #fff; }

.project__title small {
  font: 10px var(--mono);
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--soft);
  transition: color .4s;
}
.project:hover .project__title small { color: rgba(255, 255, 255, .8); }

.project__bottom {
  position: relative;
  z-index: 2;
  margin-top: 18px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  transition: border-color .4s, color .4s;
}
.project:hover .project__bottom { border-color: rgba(255, 255, 255, .4); }

.project__open b {
  display: inline-block;
  margin-left: 5px;
  font-size: 14px;
  font-weight: 400;
  transition: transform .4s var(--ease);
}
.project:hover .project__open b { transform: translate(3px, -3px); }

/* ---- shatter layer ---- */
.shatter {
  position: fixed;
  inset: 0;
  z-index: 92;
  pointer-events: none;
}

/* No overflow clipping here: the shards must be free to fly outside the
   card's original footprint. */
.shard-box { position: fixed; }

.shard {
  position: absolute;
  background-repeat: no-repeat;
  will-change: transform, opacity;
}

/* ---------- 7b. guidewire ---------- */
.gw { padding: 8vw var(--gutter) 9vw; }

.gw__grid {
  display: grid;
  grid-template-columns: minmax(0, 380px) minmax(0, 1fr);
  gap: 5vw;
  margin-top: 58px;
  align-items: start;
}

/* The role block reads as a plate: ruled off, slightly recessed, so the
   employment sits apart from the practice areas beside it. */
.gw__lead {
  padding: 28px 26px 30px;
  border: 1px solid var(--line);
  background: var(--paper-2);
}

.gw__role {
  margin: 0;
  font: 500 clamp(26px, 2.6vw, 34px)/1.1 var(--serif);
  letter-spacing: -.04em;
}

.gw__org,
.gw__dates {
  margin: 10px 0 0;
  font: 10px var(--mono);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--soft);
}

.gw__dates { margin-top: 4px; }

.gw__body {
  margin: 20px 0 0;
  font-size: 15px;
  line-height: 1.55;
  color: var(--soft);
}

.gw__body .text-blue,
.gw__body .text-coral,
.gw__body .text-green { font-weight: 500; }

/* The award is not a certificate, so it gets its own line above them
   rather than another chip in the row. */
.gw__award {
  margin: 26px 0 0;
  padding: 20px 0 0;
  border-top: 1px solid var(--line);
}

.gw__award-label {
  display: block;
  margin-bottom: 8px;
  font: 10px var(--mono);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--coral);
}

.gw__award strong {
  display: block;
  font: 400 clamp(20px, 2vw, 25px)/1.2 var(--serif);
  font-weight: 500;
  letter-spacing: -.035em;
  color: var(--ink);
}

.gw__award-org {
  display: block;
  margin-top: 5px;
  font: 10px var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--soft);
}

html:not(.dark) .gw__award strong { font-weight: 400; }

.gw__certs {
  list-style: none;
  margin: 22px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.gw__certs li {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 12px 6px 10px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  font: 500 10px var(--mono);
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink);
}

.gw__certs li::before {
  content: "";
  width: 4px;
  height: 4px;
  border-radius: 1px;
  background: var(--green);
}

/* Practice areas, numbered off the list itself rather than by hand. */
.gw__areas {
  list-style: none;
  counter-reset: area;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line);
}

.gw__areas li {
  counter-increment: area;
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr);
  gap: 6px 20px;
  padding: 24px 0;
  border-bottom: 1px solid var(--line);
}

.gw__areas li::before {
  content: counter(area, decimal-leading-zero);
  grid-row: 1 / span 2;
  font: 10px var(--mono);
  letter-spacing: .1em;
  color: var(--coral);
  padding-top: .5em;
}

.gw__areas h3 {
  margin: 0;
  font: 500 clamp(21px, 2vw, 27px)/1.15 var(--serif);
  letter-spacing: -.04em;
}

.gw__areas p {
  margin: 0;
  font-size: 15px;
  line-height: 1.55;
  color: var(--soft);
  max-width: 56ch;
}

/* ---------- 8. stack ---------- */
.stack {
  padding: 8vw var(--gutter) 9vw;
  background: var(--paper-2);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.stack__list { margin: 58px 0 0; border-top: 1px solid var(--line); }

.stack__row {
  display: grid;
  grid-template-columns: minmax(0, 250px) minmax(0, 1fr);
  gap: 24px 40px;
  padding: 26px 0;
  border-bottom: 1px solid var(--line);
}

.stack__row dt {
  font: 500 clamp(21px, 2vw, 27px)/1.15 var(--serif);
  letter-spacing: -.04em;
}

.stack__row dd {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
}

.stack__row dd span {
  padding: 7px 12px;
  border: 1px solid var(--line);
  border-radius: 100px;
  font: 10px var(--mono);
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--soft);
  /* colour only — nothing here triggers layout on hover */
  transition: color .25s, border-color .25s, background-color .25s;
}

.stack__row dd span:hover { color: var(--ink); border-color: var(--ink); }

/* the things worth spotting first */
.stack__row dd span.is-key {
  color: var(--ink);
  border-color: color-mix(in srgb, var(--coral) 55%, transparent);
}
.stack__row dd span.is-key:hover { background: var(--coral); border-color: var(--coral); color: var(--paper); }

.stack__row dd span i {
  font-style: normal;
  opacity: .6;
  margin-left: 5px;
}

/* ---------- 9. about + stats ---------- */
.about {
  padding: 8vw var(--gutter) 9vw;
  display: grid;
  grid-template-columns: 1fr minmax(300px, 520px);
  gap: 6vw;
  align-items: start;
}

.about__body p {
  margin: 22px 0 0;
  font-size: clamp(17px, 1.7vw, 22px);
  line-height: 1.45;
  letter-spacing: -.025em;
  max-width: 46ch;
}

.stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); }

.stat { padding: 26px 22px 28px; background: var(--paper); }

.stat__num {
  display: block;
  font: 500 clamp(46px, 5vw, 76px)/1 var(--serif);
  letter-spacing: -.06em;
}

.stat:nth-child(1) .stat__num { color: var(--coral); }
.stat:nth-child(2) .stat__num { color: var(--blue); }
.stat:nth-child(3) .stat__num { color: var(--green); }

/* A single figure carries the column on its own, so it is set as a
   statement rather than left as one filled cell in an empty grid. The box
   hugs its contents: stretched across the column it was mostly empty. */
.stats--single {
  grid-template-columns: minmax(0, 1fr);
  width: fit-content;
}

.stats--single .stat { padding: 22px 26px 24px; }

.stats--single .stat__num {
  font-size: clamp(68px, 8vw, 108px);
  line-height: .82;
  color: var(--coral);
}

.stats--single .stat__label {
  margin-top: 12px;
  font-size: 10px;
  letter-spacing: .12em;
}
.stat__num sup { font-size: .42em; vertical-align: super; color: var(--coral); }

.stat__label {
  display: block;
  margin-top: 10px;
  font: 10px var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--soft);
}

/* ---------- 10. footer ---------- */
/* Inverted block: the page has been cream the whole way down, and the
   contact panel is the one place it should turn. Local tokens so every
   rule and muted line inside it flips with it. */
.foot {
  --line: rgba(247, 240, 221, .2);
  --soft: rgba(247, 240, 221, .58);
  padding: 0 var(--gutter) 34px;
  background: #17140e;
  color: #f7f0dd;
}

.dark .foot { background: #0d0b08; }

.foot__title {
  padding-top: 7vw;
  font: 600 clamp(76px, 14vw, 205px)/.8 var(--serif);
  letter-spacing: -.09em;
}

.foot__title em { color: var(--coral); }
.foot__title em { font-weight: 500; }

.foot__mail {
  position: relative;
  display: inline-block;
  margin: 46px 0 34px;
  padding-bottom: 6px;
  font-size: clamp(18px, 2.4vw, 36px);
  letter-spacing: -.045em;
  overflow: hidden;
}

.foot__mail::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform-origin: right;
  transition: transform .5s var(--ease);
}
.foot__mail:hover::after { transform: scaleX(0); transform-origin: left; }

/* Email is the headline; call and LinkedIn sit under it so someone can pick
   the channel that suits them rather than only writing. */
.foot__channels {
  list-style: none;
  margin: 0 0 84px;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 14px 56px;
}

.foot__channels li {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.foot__channels i {
  font: 10px var(--mono);
  font-style: normal;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--soft);
}

.foot__channels a {
  position: relative;
  align-self: start;
  padding-bottom: 4px;
  font-size: clamp(15px, 1.5vw, 20px);
  letter-spacing: -.01em;
  border-bottom: 1px solid color-mix(in srgb, currentColor 28%, transparent);
  transition: border-color .35s var(--ease);
}

.foot__channels a span {
  display: inline-block;
  font-size: .8em;
  transition: transform .4s var(--ease);
}

.foot__channels a:hover { border-bottom-color: currentColor; }
.foot__channels a:hover span { transform: translate(3px, -3px); }

.foot__row {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
  font: 10px var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--soft);
}

.foot__row a:hover { color: #f7f0dd; }

/* ---------- 11. reveal modal ---------- */
.reveal {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: grid;
  grid-template-columns: minmax(260px, .8fr) minmax(300px, 1fr);
  align-items: center;
  gap: 6vw;
  padding: 90px var(--gutter);
  background: color-mix(in srgb, var(--paper) 94%, transparent);
  backdrop-filter: blur(20px);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  overflow: auto;
  transition: opacity .4s var(--ease), visibility .4s;
}

.reveal.is-open { opacity: 1; visibility: visible; pointer-events: auto; }

.reveal__close {
  position: absolute;
  top: 26px;
  right: var(--gutter);
  width: 44px;
  height: 44px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: inherit;
  font-size: 28px;
  line-height: 1;
  cursor: pointer;
  transition: transform .35s var(--ease), background .3s;
}
.reveal__close:hover { transform: rotate(90deg); background: var(--card); }

.reveal__hd { order: 2; opacity: 0; transform: translateY(24px); transition: opacity .5s .12s, transform .6s .12s var(--ease-out); }
.reveal.is-open .reveal__hd { opacity: 1; transform: none; }

.reveal__title {
  margin: 16px 0;
  font: 500 clamp(52px, 7vw, 105px)/.85 var(--serif);
  letter-spacing: -.075em;
}

.reveal__description { max-width: 36ch; margin: 0 0 30px; font-size: 18px; line-height: 1.4; letter-spacing: -.03em; }

.reveal__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; }

.reveal__meta > span {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 12px 6px 10px;
  border: 0;
  border-radius: 4px;
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  font: 500 10px var(--mono);
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink);
}

/* small square marker instead of a floating outline pill */
.reveal__meta > span::before {
  content: "";
  width: 4px;
  height: 4px;
  border-radius: 1px;
  background: var(--coral);
  opacity: .8;
}

.reveal__links {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 22px;
}

.reveal__links .round-link { padding: 13px 17px 13px 20px; }
.reveal__links .round-link span { font-size: 14px; }

.duo {
  order: 1;
  display: flex;
  justify-content: center;
  opacity: 0;
  transform: translateY(34px) scale(.96);
  transition: opacity .55s .05s, transform .7s .05s var(--ease-out);
}
.reveal.is-open .duo { opacity: 1; transform: none; }

/* One device frame for every project. The Moksh mockup is embedded with
   ?bare=1 so it drops its own bezel instead of drawing a phone inside a
   phone; the iframe renders at its natural 390px width and is scaled to
   fit this screen exactly. */
.ph {
  --screen-w: 247px;
  --screen-h: 534px;
  --frame-w: 390px;
  position: relative;
  width: calc(var(--screen-w) + 18px);
  height: calc(var(--screen-h) + 18px);
  border: 9px solid #17150f;
  border-radius: 42px;
  background: #17150f;
  box-shadow: 0 30px 70px rgba(30, 20, 6, .34);
  overflow: hidden;
}

.ph__screen,
.ph__screen img,
.ph__screen iframe { display: block; width: 100%; height: 100%; border: 0; object-fit: cover; }

/* The Moksh mockup draws its own handset, so the portfolio's device frame
   gets out of the way entirely and the file is simply scaled to fit. */
.duo.html-mockup .ph {
  --embed-w: 454px;
  --embed-h: 926px;
  --embed-scale: .62;
  width: calc(var(--embed-w) * var(--embed-scale));
  height: calc(var(--embed-h) * var(--embed-scale));
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  overflow: visible;
}

.duo.html-mockup .ph__screen { width: 100%; height: 100%; overflow: visible; }

.duo.html-mockup .ph__screen iframe {
  width: var(--embed-w);
  height: var(--embed-h);
  transform: scale(var(--embed-scale));
  transform-origin: top left;
}

/* An html mockup with no handset of its own renders at its natural width
   inside the device frame and is scaled down to the screen. */
.duo.framed-mockup .ph__screen { overflow: hidden; }

.duo.framed-mockup .ph__screen iframe {
  width: var(--frame-w);
  height: calc(var(--screen-h) * var(--frame-w) / var(--screen-w));
  transform: scale(calc(var(--screen-w) / var(--frame-w)));
  transform-origin: top left;
}

.reveal__placeholder { grid-column: 1 / -1; font: italic 30px var(--serif); }

/* ---------- otter ---------- */
/* The avatar is the rice card artwork, framed on the otter's head rather than
   shipped again as a second file: percentages, so it holds at any size. */
.otter__face {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: url("assets/opt/rice-otter.jpg") 53.6% 49.6% / 235% auto no-repeat;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .25);
}

.otter__face--sm { width: 30px; height: 30px; }

.otter {
  position: fixed;
  right: clamp(16px, 3vw, 30px);
  bottom: clamp(16px, 3vw, 30px);
  z-index: 85;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 7px 18px 7px 7px;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: var(--paper);
  color: var(--ink);
  box-shadow: 0 12px 34px rgba(0, 0, 0, .16);
  cursor: pointer;
  transition: transform .4s var(--ease), opacity .35s var(--ease);
}

.otter__label {
  font: 11px var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
}

.otter:hover { transform: translateY(-3px); }

/* Out of the way while the panel it opens is up. */
.otter.is-open { opacity: 0; pointer-events: none; transform: translateY(10px); }

.otter-panel {
  position: fixed;
  right: clamp(16px, 3vw, 30px);
  bottom: clamp(16px, 3vw, 30px);
  z-index: 86;
  width: min(360px, calc(100vw - 32px));
  max-height: min(560px, calc(100svh - 120px));
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: 20px;
  background: var(--paper);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .22);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(14px) scale(.98);
  transform-origin: bottom right;
  transition: opacity .32s var(--ease), transform .38s var(--ease), visibility 0s .38s;
}

.otter-panel.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: none;
  transition: opacity .32s var(--ease), transform .38s var(--ease), visibility 0s;
}

.otter-panel__top {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 14px 14px 12px;
  border-bottom: 1px solid var(--line);
}

.otter-panel__who { display: flex; flex-direction: column; gap: 2px; }
.otter-panel__who b { font: 500 15px/1 var(--sans); }
.otter-panel__who i {
  font: 10px var(--mono);
  font-style: normal;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--soft);
}

.otter-panel__close {
  margin-left: auto;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--soft);
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
  transition: background .3s, color .3s;
}

.otter-panel__close:hover { background: var(--card); color: var(--ink); }

.otter-panel__log {
  flex: 1;
  overflow-y: auto;
  padding: 16px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: 14px;
  line-height: 1.45;
  overscroll-behavior: contain;
}

.otter-msg {
  max-width: 88%;
  padding: 10px 13px;
  border-radius: 15px;
  animation: otterIn .4s var(--ease-out) both;
}

.otter-msg--bot {
  align-self: flex-start;
  border-bottom-left-radius: 5px;
  background: var(--card);
}

.otter-msg--you {
  align-self: flex-end;
  border-bottom-right-radius: 5px;
  background: var(--ink);
  color: var(--paper);
}

.otter-msg a { text-decoration: underline; text-underline-offset: 3px; }

@keyframes otterIn {
  from { opacity: 0; transform: translateY(7px); }
  to   { opacity: 1; transform: none; }
}

.otter-dots { display: flex; gap: 4px; padding: 2px 0; }
.otter-dots b {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--soft);
  animation: otterDot 1.1s ease-in-out infinite;
}
.otter-dots b:nth-child(2) { animation-delay: .16s; }
.otter-dots b:nth-child(3) { animation-delay: .32s; }

@keyframes otterDot {
  0%, 60%, 100% { opacity: .3; transform: translateY(0); }
  30%           { opacity: 1;  transform: translateY(-3px); }
}

.otter-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  padding-top: 2px;
}

.otter-actions a {
  padding: 7px 13px;
  border: 1px solid var(--ink);
  border-radius: 100px;
  font: 11px var(--mono);
  letter-spacing: .08em;
  text-transform: uppercase;
  transition: background .3s var(--ease), color .3s var(--ease);
}

.otter-actions a:hover { background: var(--ink); color: var(--paper); }

.otter-panel__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 12px 14px 14px;
  border-top: 1px solid var(--line);
}

.otter-panel__chips button {
  padding: 7px 12px;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: transparent;
  color: var(--soft);
  font: 12px var(--sans);
  cursor: pointer;
  transition: border-color .3s, color .3s, background .3s;
}

.otter-panel__chips button:hover {
  border-color: var(--ink);
  color: var(--ink);
  background: var(--card);
}

.otter-panel__chips[inert] { opacity: .5; }

/* ---------- 12. motion utilities ---------- */
[data-reveal] {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity .8s var(--ease-out), transform .9s var(--ease-out);
}
[data-reveal].is-in { opacity: 1; transform: none; }

[data-reveal-stagger] > * {
  opacity: 0;
  transform: translateY(34px);
  transition: opacity .75s var(--ease-out), transform .85s var(--ease-out);
}
[data-reveal-stagger].is-in > * { opacity: 1; transform: none; }
[data-reveal-stagger].is-in > *:nth-child(2) { transition-delay: .09s; }
[data-reveal-stagger].is-in > *:nth-child(3) { transition-delay: .18s; }
[data-reveal-stagger].is-in > *:nth-child(4) { transition-delay: .27s; }
[data-reveal-stagger].is-in > *:nth-child(5) { transition-delay: .36s; }

/* ---------- responsive ---------- */
@media (max-width: 860px) {
  .stack__row { grid-template-columns: 1fr; gap: 14px; }
  .gw__grid { grid-template-columns: 1fr; gap: 34px; }
}

@media (max-width: 900px) {
  .deck { height: auto; display: flex; flex-direction: column; gap: 14px; perspective: none; }
  .project {
    position: relative;
    width: 100%;
    height: 300px;
    transform: none;
  }
  .about { grid-template-columns: 1fr; gap: 44px; }
}

@media (max-width: 700px) {
  :root { --gutter: 20px; }
  .nav { padding: 16px var(--gutter); }
  .nav__links { display: none; }
  .nav__burger { display: flex; }
  .menu { display: flex; }
  .theme-toggle { font-size: 0; gap: 0; }
  .theme-toggle span { width: 16px; height: 16px; }

  .hero { padding: 96px var(--gutter) 44px; gap: 34px; }
  .hero__name { font-size: clamp(68px, 20vw, 112px); }
  .hero__top { flex-direction: column; align-items: flex-start; gap: 10px; }
  .hero__foot { grid-template-columns: 1fr; gap: 34px; }
  .hero__lede { font-size: 20px; max-width: none; }
  .hero__actions { margin-top: 22px; }
  .hero__actions .round-link { flex: 1 1 auto; justify-content: space-between; }
  .hero__coordinate { display: none; }
  .hero__canvas { opacity: .45; }
  /* The bust comes to the phone too, scaled rather than dropped. He holds a
     band under the masthead, the name reads across him exactly as it does on
     a desktop, and the foot keeps everything below to itself.

     The masthead leaves the flow so the band begins at a known offset: the
     canvas is absolute and has to line up with the name, which is not. */
  .has-model .hero {
    --band-top: 132px;
    --band-h: min(40svh, 330px);
    padding-top: var(--band-top);
  }

  .has-model .hero__top {
    position: absolute;
    top: 88px;
    left: var(--gutter);
    right: var(--gutter);
  }

  .has-model .hero__model {
    display: block;
    inset: var(--band-top) 0 auto 0;
    height: var(--band-h);
    width: 100%;
  }

  /* Krishna stays in the flow so the foot follows him without a spacer;
     relative + z-index 0 is what puts him behind the canvas. */
  .has-model .hero__name {
    position: relative;
    inset: auto;
    z-index: 0;
    height: var(--band-h);
    margin: 0;
    font: 500 clamp(52px, 19vw, 112px)/.84 var(--serif-hero);
    letter-spacing: -.05em;
  }

  .has-model .hero__name-echo {
    inset: var(--band-top) 0 auto 0;
    height: var(--band-h);
    font: 500 clamp(52px, 19vw, 112px)/.84 var(--serif-hero);
    letter-spacing: -.05em;
  }

  .hero__index b { font-size: 22px; }
  .peek { display: none; }

  /* On a phone it is a sheet, not a bubble in the corner. */
  .otter { right: 16px; bottom: 16px; }
  .otter-panel {
    right: 8px;
    left: 8px;
    bottom: 8px;
    width: auto;
    max-height: min(72svh, 620px);
  }

  .work { padding: 80px var(--gutter); }
  .section-head h2 { font-size: clamp(57px, 17vw, 92px); }
  .work-intro { margin: 42px 0; }
  .project__title em { font-size: 40px; }

  .stats { grid-template-columns: 1fr 1fr; }
  /* single column here too, or the two 1fr tracks from .stats above widen
     the fit-content box to twice what it needs */
  .stats--single { grid-template-columns: minmax(0, 1fr); }
  .stats--single .stat { padding: 20px 22px 22px; }

  .gw__grid { grid-template-columns: 1fr; gap: 30px; margin-top: 42px; }
  .gw__lead { padding: 22px 20px 24px; }
  .gw__areas li { grid-template-columns: 32px minmax(0, 1fr); gap: 4px 14px; padding: 20px 0; }

  .stack__list { margin-top: 42px; }
  .stack__row { grid-template-columns: 1fr; gap: 14px; padding: 22px 0; }

  .foot__title { padding-top: 80px; line-height: .85; }
  .foot__mail { margin: 32px 0 64px; }
  .foot__row { flex-direction: column; gap: 8px; }

  .reveal { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 28px; padding: 84px var(--gutter) 40px; }
  .reveal__hd { order: 1; text-align: center; }
  .reveal__description { font-size: 16px; margin-inline: auto; }
  .reveal__meta { justify-content: center; }
  .reveal__links { justify-content: center; }
  .duo { order: 2; }
  .ph { --screen-w: 215px; --screen-h: 465px; }
  .duo.html-mockup .ph { --embed-scale: .52; }
  .reveal__placeholder { font-size: 24px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .line > span { transform: none; }
  [data-reveal], [data-reveal-stagger] > * { opacity: 1; transform: none; }
}


/* ============================================================
   13. light theme
   The dark theme keeps the cinematic treatment: a fanned deck of cards
   over a drifting field. Light is set as editorial print instead, so the
   two themes read as two designs rather than one design inverted.
   ============================================================ */

html:not(.dark) {
  --serif: var(--display);
}

/* ---- work: an index, not a deck ---- */
html:not(.dark) .deck {
  position: relative;
  height: auto;
  display: block;
  perspective: none;
  border-top: 1px solid var(--ink);
}

html:not(.dark) .project {
  position: relative;
  width: 100%;
  height: auto;
  min-height: 132px;
  display: grid;
  grid-template-columns: 74px minmax(0, 1fr) minmax(0, 42%);
  align-items: center;
  gap: 30px;
  padding: 30px 26px 30px 0;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  transform: none;
  transition: color .45s var(--ease), padding-left .5s var(--ease);
}

/* the artwork arrives as a band across the whole row */
html:not(.dark) .project::before {
  inset: 0;
  border-radius: 0;
  background: linear-gradient(90deg, rgba(8, 8, 8, .82), rgba(8, 8, 8, .45)), var(--image) center/cover;
}

html:not(.dark) .project:hover {
  color: #fff;
  padding-left: 26px;
  box-shadow: none;
}

html:not(.dark) .project::after { display: none; }

html:not(.dark) .project__top {
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
}

html:not(.dark) .project__title {
  margin: 0;
  gap: 7px;
}

html:not(.dark) .project__title em {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(40px, 5.6vw, 80px);
  line-height: .95;
  letter-spacing: -.03em;
}

html:not(.dark) .project__bottom {
  margin: 0;
  padding: 0;
  border: 0;
  justify-content: space-between;
}

html:not(.dark) .project:hover .project__bottom { border-color: transparent; }

/* ---- section heads and the rest pick up the display face ---- */
html:not(.dark) .section-head h2,
html:not(.dark) .foot__title,
html:not(.dark) .reveal__title {
  font-weight: 400;
  letter-spacing: -.02em;
}

html:not(.dark) .gw__role,
html:not(.dark) .gw__areas h3,
html:not(.dark) .stack__row dt,
html:not(.dark) .stat__num {
  font-weight: 400;
}

@media (max-width: 860px) {
  /* Stacked rather than columnar: at this width the index column starved and
     broke "01 / APP_001" across three lines. */
  html:not(.dark) .project {
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
    min-height: 0;
    padding: 22px 16px 22px 0;
  }
  html:not(.dark) .project__top {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    width: 100%;
  }
  html:not(.dark) .project__bottom { margin-top: 4px; }
  html:not(.dark) .project:hover { padding-left: 16px; }
  html:not(.dark) .project__title em { font-size: clamp(34px, 11vw, 52px); }
}

/* ---------- 15. touch: the artwork is not behind a hover ----------
   Every card carries its artwork under a hover, which a finger cannot
   perform. Where there is no hover the artwork is simply on, and the
   states that rode with it come too. */
@media (hover: none) {
  .project::before { opacity: 1; }

  .project,
  html:not(.dark) .project {
    color: #fff;
    border-color: transparent;
  }

  .project__top,
  .project__bottom,
  .project__title small {
    color: rgba(255, 255, 255, .8);
  }

  .project__title em,
  .dark .project--rice .project__title em,
  .dark .project--moksh .project__title em,
  .dark .project--mecha .project__title em,
  .project--rice .project__title em,
  .project--moksh .project__title em,
  .project--mecha .project__title em {
    color: #fff;
  }

  .project__bottom { border-top-color: rgba(255, 255, 255, .3); }

  /* The light row is a band of artwork rather than a rule between rows. */
  html:not(.dark) .project {
    border-bottom-color: transparent;
    padding-left: 16px;
    margin-bottom: 10px;
    border-radius: 4px;
    overflow: hidden;
  }

  html:not(.dark) .project__bottom { border: 0; }
}
