/* =============================================================================
   DARSHI SHAH — PORTFOLIO BASE & SHARED PRIMITIVES
   Reset, fonts, the shared "atmosphere" (orbs / grain / fade / cursor orb), and
   reusable primitives (marker highlight, serif accent, glass surface, buttons,
   cards, nav). Everything here reads from tokens.css — NO hardcoded values.

   Load order in every page:
     1) Google Fonts <link> (or self-hosted @font-face)
     2) tokens.css
     3) base.css
     4) page-specific styles (which should also only use tokens)
   ========================================================================== */

/* ───────────────────────── RESET ───────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

html {
  /* smooth in-page anchor scrolling, but never override a reduced-motion user */
  scroll-behavior: smooth;
  /* avoid iOS auto-inflating text on rotate; respect user zoom */
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--color-paper);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-weight: var(--weight-body);
  font-size: var(--text-body);
  line-height: var(--leading-relaxed);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  /* never let a stray wide element force a sideways scroll on small screens */
  max-width: 100vw;
}
::selection { background: var(--color-selection); }

a { color: inherit; }

/* media is fluid by default — scales down with the viewport, never overflows */
img, svg, video, canvas, iframe { max-width: 100%; height: auto; }
img, video { display: block; }


/* ───────────────────────── ACCESSIBILITY ─────────────────────────
   Site-wide rules for keyboard, screen-reader, and touch users. Every page
   inherits these — don't remove focus outlines in page CSS. */

/* Visible keyboard focus on anything interactive. Mouse clicks stay clean
   (:focus-visible only paints for keyboard / programmatic focus). */
:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--radius-xs);
}
/* kill the default ring only where :focus-visible has replaced it */
:focus:not(:focus-visible) { outline: none; }

/* In-page anchors land below the header instead of flush to the top edge. */
:target { scroll-margin-top: var(--scroll-offset); }

/* Skip-to-content link: visually hidden until focused, first thing in <body>.
   Add  <a class="skip-link" href="#main">Skip to content</a>  as the first
   child of <body>, and give the main content  id="main". */
.skip-link {
  position: absolute;
  left: var(--space-4); top: calc(-1 * var(--space-12));
  z-index: var(--z-tooltip);
  padding: var(--space-2) var(--space-4);
  background: var(--color-ink);
  color: var(--color-surface);
  border-radius: var(--radius-xs);
  font-family: var(--font-display);
  font-size: var(--text-small);
  text-decoration: none;
  transition: top var(--dur-fast) var(--ease-std);
}
.skip-link:focus { top: var(--space-4); }

/* Screen-reader-only text (labels for icon-only controls, etc.). */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}


/* ───────────────────────── TYPOGRAPHY PRIMITIVES ───────────────────────── */
.h1, .h2, .h3 {
  font-family: var(--font-display);
  color: var(--color-ink);
  margin: 0;
}
.h1 { font-weight: var(--weight-hero); font-size: var(--text-hero); line-height: var(--leading-tight); letter-spacing: var(--tracking-hero); text-wrap: balance; }
.h2 { font-weight: var(--weight-h2);   font-size: var(--text-h2);   line-height: var(--leading-snug); letter-spacing: var(--tracking-tight); }
.h3 { font-weight: var(--weight-h2);   font-size: var(--text-h3);   line-height: var(--leading-snug); letter-spacing: var(--tracking-tight); }

.lead {
  font-size: var(--text-lead);
  line-height: var(--leading-relaxed);
  letter-spacing: var(--tracking-normal);
  color: var(--color-ink-sub);
  max-width: var(--maxw-text);
  text-wrap: pretty;
}
.body { color: var(--color-ink-sub); max-width: var(--maxw-text); }

/* Case-study intro paragraph: the lead that follows the case title spans the
   full content width instead of the narrow readable measure. Case studies only. */
.case-summary { max-width: var(--maxw-content); }

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-eyebrow);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

/* publication / institution accent — Noto Serif italic, heavier */
.serif-em {
  font-family: var(--font-serif);
  font-weight: 600;
  font-style: italic;
  color: var(--color-ink);
  letter-spacing: 0;
}
.mono { font-family: var(--font-mono); }


/* ───────────────────────── LAYOUT HELPERS ───────────────────────── */
.section {
  position: relative;
  z-index: var(--z-content);
  padding: var(--space-9) var(--gutter) var(--space-12);
}
.container { max-width: var(--maxw-content); margin: 0 auto; }
.measure   { max-width: var(--maxw-text); }


/* ───────────────────────── STAGE & ATMOSPHERE ─────────────────────────
   Wrap a page (or a run of sections) in .stage and drop the .atmos block in
   first. The warm orb field, grain, and white fade then bleed across it. */
.stage { position: relative; }

.atmos {
  position: absolute; inset: 0;
  z-index: var(--z-atmos);
  overflow: hidden;
  pointer-events: none;
}
.orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(var(--blur-orb));
  will-change: transform;
}
.orb--a {
  width: 62vmax; height: 62vmax;
  top: -20vmax; left: -16vmax;
  background: radial-gradient(circle at 28% 30%, var(--color-orb-a) 0%, color-mix(in oklab, var(--color-orb-a) 40%, transparent) 42%, transparent 70%);
  animation: orbA var(--orb-dur-a) linear infinite;
}
.orb--b {
  width: 54vmax; height: 54vmax;
  top: -12vmax; right: -18vmax;
  background: radial-gradient(circle at 70% 32%, var(--color-orb-b) 0%, color-mix(in oklab, var(--color-orb-b) 38%, transparent) 44%, transparent 72%);
  animation: orbB var(--orb-dur-b) linear infinite;
}
.orb--c {
  width: 58vmax; height: 58vmax;
  top: 52vh; left: 14vmax;
  background: radial-gradient(circle at 40% 56%, var(--color-orb-c) 0%, color-mix(in oklab, var(--color-orb-c) 36%, transparent) 46%, transparent 72%);
  animation: orbC var(--orb-dur-c) linear infinite;
}

@keyframes orbA {
  0%   { transform: translate(0,0)            rotate(0deg)   scale(1);    opacity: 0.82; }
  20%  { transform: translate(13vmax, 9vmax)  rotate(72deg)  scale(1.5);  opacity: 1;    }
  40%  { transform: translate(23vmax, 21vmax) rotate(144deg) scale(1.0);  opacity: 0.85; }
  60%  { transform: translate(9vmax, 29vmax)  rotate(216deg) scale(0.6);  opacity: 0.5;  }
  80%  { transform: translate(-7vmax, 13vmax) rotate(288deg) scale(1.08); opacity: 0.82; }
  100% { transform: translate(0,0)            rotate(360deg) scale(1);    opacity: 0.82; }
}
@keyframes orbB {
  0%   { transform: translate(0,0)             rotate(0deg)    scale(1);    opacity: 0.8;  }
  20%  { transform: translate(-15vmax, 8vmax)  rotate(-72deg)  scale(1.45); opacity: 1;    }
  40%  { transform: translate(-24vmax, 20vmax) rotate(-144deg) scale(0.95); opacity: 0.82; }
  60%  { transform: translate(-10vmax, -6vmax) rotate(-216deg) scale(0.6);  opacity: 0.48; }
  80%  { transform: translate(2vmax, -14vmax)  rotate(-288deg) scale(1.1);  opacity: 0.85; }
  100% { transform: translate(0,0)             rotate(-360deg) scale(1);    opacity: 0.8;  }
}
@keyframes orbC {
  0%   { transform: translate(0,0)             rotate(0deg)   scale(1);    opacity: 0.82; }
  20%  { transform: translate(16vmax, -12vmax) rotate(60deg)  scale(1.5);  opacity: 1;    }
  40%  { transform: translate(24vmax, -22vmax) rotate(140deg) scale(1.0);  opacity: 0.82; }
  60%  { transform: translate(8vmax, 8vmax)    rotate(210deg) scale(0.58); opacity: 0.5;  }
  80%  { transform: translate(-14vmax, 4vmax)  rotate(300deg) scale(1.08); opacity: 0.84; }
  100% { transform: translate(0,0)             rotate(360deg) scale(1);    opacity: 0.82; }
}

/* cursor-following orb — accent colour, denser core, less blur */
.orb--cursor {
  position: fixed;
  top: 0; left: 0;
  width: 12vmax; height: 12vmax;
  margin: -6vmax 0 0 -6vmax;
  border-radius: 50%;
  z-index: var(--z-cursor);
  filter: blur(var(--blur-cursor));
  opacity: 0.425;
  pointer-events: none;
  will-change: transform;
  transform: translate(-50vw, -50vh);
  background: radial-gradient(circle at 50% 46%,
    var(--color-accent) 0%,
    color-mix(in oklab, var(--color-accent) 78%, transparent) 26%,
    color-mix(in oklab, var(--color-accent) 32%, transparent) 52%,
    transparent 70%);
}

/* one continuous fade resolving to white below the hero */
.fade {
  position: absolute; left: 0; right: 0; top: 0;
  height: 100%; z-index: var(--z-fade); pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(255,255,255,0) 0vh,
    rgba(255,255,255,0) 24vh,
    rgba(255,255,255,0.45) 64vh,
    rgba(255,255,255,0.82) 96vh,
    var(--color-surface) 124vh
  );
}

/* film grain to break gradient banding + warm the page */
.grain {
  position: absolute; inset: 0; z-index: var(--z-grain); pointer-events: none;
  opacity: var(--grain-opacity); mix-blend-mode: multiply;
  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='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* photographic vignette concentrated in the upper area */
.vignette {
  position: absolute; inset: 0; z-index: var(--z-atmos); pointer-events: none;
  mix-blend-mode: multiply;
  background: radial-gradient(125% 115% at 50% 30%, transparent 46%, rgba(74,48,22, var(--vignette-opacity)) 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 30%, transparent 70%);
          mask-image: linear-gradient(to bottom, #000 0%, #000 30%, transparent 70%);
}

/* Inner pages: freeze the three background blobs so they don't drift over
   the content. The cursor orb keeps moving; only the home page animates. */
body.static-atmos .orb--a,
body.static-atmos .orb--b,
body.static-atmos .orb--c {
  animation: none;
}
/* soften the two foreground blobs just slightly on inner pages */
body.static-atmos .orb--a,
body.static-atmos .orb--b {
  opacity: 0.85;
}

@media (prefers-reduced-motion: reduce) {
  .orb { animation: none !important; }
  .orb--cursor { display: none; }
}


/* ───────────────────────── ENTRANCE ANIMATION ───────────────────────── */
.rise { opacity: 0; animation: rise var(--dur-slow) var(--ease-rise) both; }
.rise-1 { animation-delay: 0.1s; }
.rise-2 { animation-delay: 0.3s; }
.rise-3 { animation-delay: 0.45s; }
.rise-4 { animation-delay: 0.5s; }
.rise-5 { animation-delay: 0.62s; }
@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .rise { animation: none !important; opacity: 1 !important; }
}


/* ───────────────────────── NAV / WORDMARK ───────────────────────── */
.topbar {
  position: sticky; top: 0; z-index: 40;
  transition: transform .4s cubic-bezier(.2,.7,.2,1);
  will-change: transform;
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-7) var(--gutter);
  gap: var(--space-5);
}
.topbar.nav--scrolled {
  background: color-mix(in oklab, var(--color-paper) 82%, transparent);
  backdrop-filter: saturate(140%) blur(14px);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
  box-shadow: 0 1px 0 rgba(31,31,31,0.06);
}
.topbar.nav--hidden { transform: translateY(-110%); }
.wordmark {
  font-family: var(--font-display);
  font-weight: var(--weight-head);
  font-size: var(--text-body);
  letter-spacing: var(--tracking-tight);
  color: var(--color-ink);
  text-decoration: none;
}
.nav { display: flex; align-items: center; gap: var(--space-6); }
.nav a {
  display: inline-flex; align-items: center; gap: 7px;
  font-weight: var(--weight-head);
  font-size: var(--text-small);
  letter-spacing: var(--tracking-tight);
  color: var(--color-ink-sub);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-std);
}
.nav a svg { width: 15px; height: 15px; stroke: currentColor; stroke-width: 1.6; fill: none; stroke-linecap: round; stroke-linejoin: round; opacity: 0.85; }
.nav a:hover { color: var(--color-ink); }


/* ───────────────────────── BUTTONS ───────────────────────── */
.btn {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-family: var(--font-display);
  font-weight: var(--weight-head);
  font-size: var(--text-small);
  letter-spacing: var(--tracking-tight);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-std), color var(--dur-fast) var(--ease-std), border-color var(--dur-fast) var(--ease-std);
}
.btn--primary { background: var(--color-ink); color: var(--color-surface); }
.btn--primary:hover { background: var(--color-ink-strong); }
.btn--ghost { background: transparent; color: var(--color-ink); border-color: var(--color-card-border); }
.btn--ghost:hover { border-color: var(--color-ink); }


/* ───────────────────────── GLASS SURFACE ─────────────────────────
   Liquid-glass panel (the pronunciation tooltip uses this). Reusable for
   callouts, popovers, pull-quotes. */
.glass {
  background: color-mix(in oklab, var(--color-accent) 16%, rgba(255,255,255,0.40));
  -webkit-backdrop-filter: blur(var(--blur-glass)) saturate(1.7);
          backdrop-filter: blur(var(--blur-glass)) saturate(1.7);
  border: 1px solid rgba(255,255,255,0.55);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-glass);
  position: relative;
  overflow: hidden;
}
.glass::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(135deg, rgba(255,255,255,0.55), rgba(255,255,255,0) 42%);
}


/* ───────────────────────── CARDS ───────────────────────── */
.card-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--grid-gap);
  max-width: var(--maxw-content);
}
.card { display: flex; flex-direction: column; }
.card-shot {
  aspect-ratio: 16 / 11;
  border-radius: var(--radius-xs);
  border: 1px solid var(--color-card-border);
  background-color: var(--color-card);
  background-image: repeating-linear-gradient(135deg, var(--color-hatch) 0 1px, transparent 1px 11px);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}
.card-shot img { width: 100%; height: 100%; object-fit: cover; }
.card-meta { padding: var(--space-4) 2px 0; }
.card-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--weight-head);
  font-size: var(--text-title);
  letter-spacing: var(--tracking-tight);
  color: var(--color-ink);
}
.card-sub {
  margin: 6px 0 0;
  font-weight: var(--weight-body);
  font-size: var(--text-small);
  color: var(--color-ink-sub);
}


/* ───────────────────────── ORGANIC MARKER HIGHLIGHT ─────────────────────────
   Wrap a word in <span class="mark">…</span> for the felt-tip swipe behind the
   ink. The .mark--* modifiers add slight per-instance rotation so repeated
   strokes don't look stamped. */
.mark {
  position: relative;
  isolation: isolate;
  white-space: nowrap;
  padding: 0 0.06em;
}
.mark::before,
.mark::after {
  content: "";
  position: absolute;
  z-index: -1;
  left: -0.18em; right: -0.18em;
  top: -0.16em; bottom: -0.13em;
  background: var(--color-accent);
  mix-blend-mode: multiply;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
}
.mark::before {
  opacity: 0.62;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 120' preserveAspectRatio='none'%3E%3Cfilter id='b' x='-8%25' y='-30%25' width='116%25' height='160%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.013 0.026' numOctaves='2' seed='7' result='w'/%3E%3CfeDisplacementMap in='SourceGraphic' in2='w' scale='22'/%3E%3C/filter%3E%3Crect x='12' y='30' width='296' height='60' rx='30' fill='%23000' filter='url(%23b)'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 120' preserveAspectRatio='none'%3E%3Cfilter id='b' x='-8%25' y='-30%25' width='116%25' height='160%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.013 0.026' numOctaves='2' seed='7' result='w'/%3E%3CfeDisplacementMap in='SourceGraphic' in2='w' scale='22'/%3E%3C/filter%3E%3Crect x='12' y='30' width='296' height='60' rx='30' fill='%23000' filter='url(%23b)'/%3E%3C/svg%3E");
}
.mark::after {
  opacity: 0.4;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 120' preserveAspectRatio='none'%3E%3Cfilter id='s' x='-8%25' y='-30%25' width='116%25' height='160%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.012 0.024' numOctaves='2' seed='3' result='w'/%3E%3CfeDisplacementMap in='SourceGraphic' in2='w' scale='20' result='shape'/%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.02 0.45' numOctaves='2' seed='9' result='g'/%3E%3CfeColorMatrix in='g' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.9 -0.18' result='ga'/%3E%3CfeComposite in='shape' in2='ga' operator='arithmetic' k1='1' k2='0' k3='0' k4='0'/%3E%3C/filter%3E%3Crect x='14' y='34' width='292' height='52' rx='26' fill='%23000' filter='url(%23s)'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 120' preserveAspectRatio='none'%3E%3Cfilter id='s' x='-8%25' y='-30%25' width='116%25' height='160%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.012 0.024' numOctaves='2' seed='3' result='w'/%3E%3CfeDisplacementMap in='SourceGraphic' in2='w' scale='20' result='shape'/%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.02 0.45' numOctaves='2' seed='9' result='g'/%3E%3CfeColorMatrix in='g' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.9 -0.18' result='ga'/%3E%3CfeComposite in='shape' in2='ga' operator='arithmetic' k1='1' k2='0' k3='0' k4='0'/%3E%3C/filter%3E%3Crect x='14' y='34' width='292' height='52' rx='26' fill='%23000' filter='url(%23s)'/%3E%3C/svg%3E");
}
.mark--a::before,  .mark--a::after  { transform: rotate(-0.5deg); }
.mark--b::before,  .mark--b::after  { transform: rotate(0.6deg) scaleX(1.02); }
.mark--c::before,  .mark--c::after  { transform: rotate(-0.8deg); }


/* ───────────────────────── RESPONSIVE ─────────────────────────
   880px is the primary mobile break for the whole site (see tokens.css
   BREAKPOINTS). Reuse this literal width in page-level @media blocks so
   everything collapses at the same point. */
@media (max-width: 880px) {
  .topbar  { padding: var(--space-5) var(--gutter-mobile); flex-wrap: wrap; gap: var(--space-3); }
  .nav     { gap: var(--space-4); }
  .section { padding: var(--space-7) var(--gutter-mobile) var(--space-11); }
  /* let marker-highlighted phrases wrap on small screens — keeping them nowrap
     forces horizontal overflow when a long phrase (e.g. in a heading) can't break. */
  .mark { white-space: normal; }
}

/* Nav collapses to icon-only below iPad-portrait width (≥768px keeps text labels,
   so every iPad shows the full nav and only phones / small tablets get icons).
   Matches the home, publications and how-i-use-ai pages, which collapse at 760. */
@media (max-width: 760px) {
  /* hide the label VISUALLY but keep it for screen readers, so each link still
     has an accessible name. */
  .nav a span {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0,0,0,0); white-space: nowrap; border: 0;
  }
  .nav a { min-width: var(--tap-min); min-height: var(--tap-min); justify-content: center; }
}

/* Phone: multi-column grids stack. 2-up card grids stay 2-up through tablet
   (better use of iPad width) and collapse here, matching the home projects grid. */
@media (max-width: 600px) {
  .card-grid { grid-template-columns: 1fr; gap: var(--space-8); }
}

/* Touch-pointer devices: every button / nav link gets a comfortable hit area,
   regardless of viewport width. */
@media (pointer: coarse) {
  .btn, .nav a { min-height: var(--tap-min); }

  /* PERF: the ambient orbs animate a huge blur(var(--blur-orb)) layer every
     frame. On mobile GPUs that pins the compositor during load and scroll and
     is the main cause of the page feeling slow. Freeze them (the static warm
     gradient stays), drop the blur radius, and release the promoted layer.
     The cursor orb is meaningless without a mouse, so remove it entirely
     (cursor-orb.js also bails on coarse pointers). */
  .orb { animation: none !important; filter: blur(60px) !important; will-change: auto !important; }
  .orb--cursor { display: none !important; }
}
