/* ==========================================================================
   vibhakarmohta, site styles
   One file. Design tokens at the top; change those and the whole site moves.
   ========================================================================== */

:root {
  /* --- palette ------------------------------------------------------- */
  --paper:      #FBFAF7;   /* page background */
  --paper-2:    #F4F2EC;   /* recessed panels */
  --card:       #FFFFFF;
  --ink:        #14161A;   /* body text */
  --ink-2:      #4A5058;   /* secondary text */
  --ink-3:      #7C838C;   /* metadata */
  --rule:       #E3DFD5;   /* hairlines */
  --rule-2:     #D3CEC1;
  --accent:     #E8721C;   /* the single accent, links, active state */
  --accent-ink: #B8540A;   /* accent, but readable on paper */
  --slate:      #3E5C76;   /* cool secondary */
  --grid:       #EAE7DE;   /* graph-paper lines */

  /* --- type ---------------------------------------------------------- */
  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo,
          Consolas, "Liberation Mono", monospace;

  /* --- metrics ------------------------------------------------------- */
  --wide:   1240px;
  --narrow: 760px;
  --pad:    clamp(1.15rem, 4vw, 2.5rem);
  --radius: 3px;          /* deliberately tight, instrument panel, not app UI */
  --t: 180ms cubic-bezier(.2, .7, .3, 1);
  --head-h: 75px;         /* sticky header height. site.js overwrites this with
                             the measured value on load; this is the no-JS
                             fallback, and matches the desktop header's 74px
                             content box plus its 1px bottom rule. */
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #131417; --paper-2: #1A1C20; --card: #1B1D22;
    --ink: #ECEAE5; --ink-2: #B4B8BF; --ink-3: #868C95;
    --rule: #2A2D33; --rule-2: #3A3E46;
    --accent: #F4913F; --accent-ink: #F4913F; --slate: #8FB0CC;
    --grid: #1E2126;
  }
}
:root[data-theme="dark"] {
  --paper: #131417; --paper-2: #1A1C20; --card: #1B1D22;
  --ink: #ECEAE5; --ink-2: #B4B8BF; --ink-3: #868C95;
  --rule: #2A2D33; --rule-2: #3A3E46;
  --accent: #F4913F; --accent-ink: #F4913F; --slate: #8FB0CC;
  --grid: #1E2126;
}

/* ==========================================================================
   base
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%; scroll-behavior: smooth;
  /* jumping to #experience must not land the heading behind the sticky header */
  scroll-padding-top: var(--head-h);
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16.5px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

a { color: var(--accent-ink); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: .18em; }

h1, h2, h3, h4 { line-height: 1.16; letter-spacing: -.021em; margin: 0; font-weight: 640; }
h1 { font-size: clamp(2.2rem, 5vw, 3.4rem); }
h2 { font-size: clamp(1.55rem, 3.1vw, 2.05rem); }
h3 { font-size: 1.22rem; }
p  { margin: 0 0 1.05em; }

::selection { background: var(--accent); color: #fff; }

.wrap   { width: 100%; max-width: var(--wide);   margin-inline: auto; padding-inline: var(--pad); }
.narrow { width: 100%; max-width: var(--narrow); margin-inline: auto; padding-inline: var(--pad); }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--paper); padding: .7em 1.1em;
}
.skip:focus { left: .5rem; top: .5rem; }

:focus-visible { outline: 3px solid var(--accent-ink); outline-offset: 2px; border-radius: 2px; }

/* the mono metadata voice used everywhere */
.mono, .eyebrow, .chip, .meta, .datecol, .linkrow a, .count {
  font-family: var(--mono);
  font-size: .76rem;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* ==========================================================================
   header / nav
   ========================================================================== */

.site-head {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--rule);
}
.site-head .wrap {
  display: flex; align-items: center; gap: 1.5rem;
  /* Deliberately a literal, not --head-h. site.js measures the header and
     writes that token, so reading it back here would make the header's height
     depend on its own measurement, and the ResizeObserver would be observing an
     element it resizes. --head-h is an output of this box, never an input. */
  min-height: 74px;
}
.brand {
  font-family: var(--mono); font-weight: 700; font-size: 1rem;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink); text-decoration: none; white-space: nowrap;
  display: inline-flex; align-items: center; gap: .55em;
}
.brand:hover { text-decoration: none; color: var(--accent-ink); }

/* The wordmark is a light painting, photographed once and reduced to an alpha
   mask, so it takes the accent colour and works on either theme. */
.brand-logo { display: none; }
@supports ((mask-image: url("")) or (-webkit-mask-image: url(""))) {
  .brand-logo {
    display: inline-block; flex: none;
    height: 1.45em; width: calc(1.45em * 1.81);
    background-color: var(--accent);
    -webkit-mask: url("../img/logo.png") no-repeat center / contain;
            mask: url("../img/logo.png") no-repeat center / contain;
  }
}
.brand:hover .brand-logo { background-color: var(--accent-ink); }

.site-nav { margin-left: auto; display: flex; align-items: center; gap: .25rem; flex-wrap: wrap; }
.site-nav a {
  font-family: var(--mono); font-size: .95rem; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-2);
  padding: .6rem .85rem; border-radius: var(--radius);
  transition: color var(--t), background var(--t);
}
.site-nav a:hover { color: var(--ink); background: var(--paper-2); text-decoration: none; }
.site-nav a[aria-current="page"] { color: var(--accent-ink); }
.site-nav a[aria-current="page"]::after {
  content: ""; display: block; height: 2px; background: var(--accent);
  margin-top: 2px; border-radius: 2px;
}

.theme-toggle {
  border: 1px solid var(--rule-2); background: transparent; color: var(--ink-2);
  font-family: var(--mono); font-size: 1.05rem; line-height: 1; letter-spacing: .08em;
  padding: .5rem .7rem; border-radius: var(--radius); cursor: pointer;
  margin-left: .35rem; transition: border-color var(--t), color var(--t);
}
.theme-toggle:hover { border-color: var(--accent); color: var(--accent-ink); }

/* Narrow screens: tighten the nav so it stays on one line under the brand
   instead of stacking into three. */
@media (max-width: 720px) {
  .site-head .wrap { gap: .5rem; padding-block: .5rem; }
  .brand { font-size: .74rem; }
  .site-nav { gap: 0; width: 100%; margin-left: 0; justify-content: space-between; }
  .site-nav a { padding: .35rem .3rem; font-size: .68rem; letter-spacing: .05em; }
  .theme-toggle { margin-left: .1rem; padding: .3rem .4rem; }
}
@media (max-width: 380px) {
  .site-nav a { font-size: .7rem; padding-inline: .25rem; }
}

/* Touch targets. Standalone controls get at least 44px of tappable height on
   phones; inline links inside prose are left alone, since padding them out
   would wreck the line spacing. */
@media (hover: none) and (pointer: coarse) {
  /* Tag chips are deliberately excluded: they are secondary filters and the
     brief was explicitly for small, short pills. */
  .site-nav a, .brand, .theme-toggle, .backlink,
  .linkrow a, .showmore, .projnav a {
    min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .site-nav a { padding-block: 0; }
  .brand { justify-content: flex-start; }
  .backlink, .projnav a { justify-content: flex-start; }
  .theme-toggle { min-width: 44px; }
  .robot .cap { min-height: 44px; }
}

/* ==========================================================================
   section scaffolding, numbered headers with a rule to the margin
   ========================================================================== */

section { padding-block: clamp(3rem, 7vw, 5.25rem); }
section + section { border-top: 1px solid var(--rule); }

.sec-head {
  display: flex; align-items: baseline; gap: 1rem;
  margin-bottom: clamp(1.6rem, 3vw, 2.4rem);
}
.sec-head .num {
  font-family: var(--mono); font-size: .88rem; letter-spacing: .1em;
  color: var(--accent-ink); white-space: nowrap;
}
.sec-head h2 { font-size: clamp(1.5rem, 3vw, 2.05rem); white-space: nowrap; }
.sec-head::after {
  content: ""; flex: 1; height: 1px; background: var(--rule-2);
  transform: translateY(-.35em);
}
.sec-head .more {
  font-family: var(--mono); font-size: .82rem; letter-spacing: .08em;
  text-transform: uppercase; white-space: nowrap;
}

/* ==========================================================================
   hero
   ========================================================================== */

.hero {
  position: relative; overflow: hidden;
  border-bottom: 1px solid var(--rule);
  padding-block: clamp(3rem, 8vw, 6rem) clamp(2rem, 5vw, 3.5rem);
}
.hero::before {                       /* graph paper, hero only */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(var(--grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  background-size: 34px 34px;
  -webkit-mask-image: radial-gradient(120% 90% at 22% 0%, #000 0%, transparent 72%);
          mask-image: radial-gradient(120% 90% at 22% 0%, #000 0%, transparent 72%);
}
.hero > * { position: relative; }

.hero-grid {
  display: grid; gap: clamp(1.75rem, 4vw, 3.25rem);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
@media (min-width: 820px) {
  .hero-grid { grid-template-columns: minmax(0, 1fr) 360px; }
}

.hero .status {
  display: inline-flex; align-items: center; gap: .55rem;
  font-family: var(--mono); font-size: .82rem; letter-spacing: .09em;
  color: var(--ink-2); margin-bottom: 1.25rem;
  border: 1px solid var(--rule-2); border-radius: 100px;
  padding: .42rem 1rem .42rem .75rem; background: var(--card);
}
.hero .status .dot {
  width: 7px; height: 7px; border-radius: 50%; background: #2FA84F;
  box-shadow: 0 0 0 0 rgba(47,168,79,.5); animation: pulse 2.6s infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(47,168,79,.45); }
  70%  { box-shadow: 0 0 0 7px rgba(47,168,79,0); }
  100% { box-shadow: 0 0 0 0 rgba(47,168,79,0); }
}

.hero h1 { margin-bottom: .5rem; }
.hero .tagline {
  font-size: clamp(1.15rem, 2.3vw, 1.4rem); color: var(--slate);
  font-weight: 500; margin-bottom: 1.5rem; max-width: none; text-wrap: balance;
  letter-spacing: -.012em;
}
.hero .bio { max-width: 62ch; color: var(--ink-2); }
.hero .bio strong { color: var(--ink); font-weight: 620; }

.portrait {
  width: 100%; max-width: 360px; aspect-ratio: 3 / 4; object-fit: cover;
  border-radius: var(--radius); border: 1px solid var(--rule-2);
  transition: transform var(--t);
}
.portrait:hover { transform: scale(1.01); }

.linkrow { display: flex; flex-wrap: wrap; gap: .45rem; margin-top: 1.5rem; }
.linkrow a {
  display: inline-flex; align-items: center; gap: .42rem;
  border: 1px solid var(--rule-2); background: var(--card);
  color: var(--ink-2); padding: .42rem .72rem; border-radius: var(--radius);
  transition: color var(--t), border-color var(--t), transform var(--t);
}
.linkrow a:hover {
  color: var(--accent-ink); border-color: var(--accent);
  text-decoration: none; transform: translateY(-1px);
}
.linkrow svg { width: 14px; height: 14px; flex: none; }

/* ==========================================================================
   robot strip, every machine, in a row
   ========================================================================== */

.robot-strip { padding-block: 0; border-top: 1px solid var(--rule); }
.robot-strip .wrap { padding-block: 1.5rem 1.75rem; }
.robot-strip .label {
  font-family: var(--mono); font-size: .82rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 1rem;
  display: flex; align-items: center; gap: .6rem;
}
.robot-strip .label::after {
  content: ""; flex: 1; height: 1px; background: var(--rule);
}
.robot-rail {
  display: flex; gap: .8rem; overflow-x: auto; padding-bottom: .6rem;
  scroll-snap-type: x proximity; scrollbar-width: thin;
}
.robot-rail::-webkit-scrollbar { height: 6px; }
.robot-rail::-webkit-scrollbar-thumb { background: var(--rule-2); border-radius: 3px; }

.robot {
  flex: 0 0 auto; width: 248px; scroll-snap-align: start;
  border: 1px solid var(--rule); border-radius: var(--radius);
  overflow: hidden; background: var(--card); text-decoration: none;
  transition: border-color var(--t), transform var(--t);
}
.robot:hover { border-color: var(--accent); transform: translateY(-2px); text-decoration: none; }
.robot img, .robot video {
  width: 100%; aspect-ratio: 16/9; object-fit: cover;
  filter: saturate(1.18) contrast(1.04); transition: filter var(--t);
}
.robot:hover img, .robot:hover video { filter: saturate(1.32) contrast(1.07); }
.robot .cap {
  padding: .5rem .6rem .6rem;
  font-family: var(--mono); font-size: .78rem; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-2); line-height: 1.4;
}
.robot .cap b { display: block; color: var(--ink); font-weight: 600; }
.robot .cap span { color: var(--ink-3); }

/* ==========================================================================
   updates feed
   ========================================================================== */

.updates { list-style: none; margin: 0; padding: 0; max-width: 78ch; }
.updates li {
  display: grid; grid-template-columns: 5.6rem minmax(0, 1fr);
  gap: 1rem; padding: .5rem 0;
  border-bottom: 1px dashed var(--rule);
}
.updates li:last-child { border-bottom: 0; }
.datecol { color: var(--accent-ink); padding-top: .3em; white-space: nowrap; }
.updates .txt { color: var(--ink-2); }
.updates .txt strong { color: var(--ink); font-weight: 620; }
@media (max-width: 540px) {
  .updates li { grid-template-columns: 1fr; gap: .1rem; padding-block: .65rem; }
  .datecol { padding-top: 0; }
}

.showmore {
  margin-top: 1.25rem; background: none; border: 0; cursor: pointer;
  font-family: var(--mono); font-size: .74rem; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent-ink); padding: .3rem 0;
}
.showmore:hover { text-decoration: underline; text-underline-offset: .2em; }
.updates li[data-extra] { display: none; }
.updates.expanded li[data-extra] { display: grid; }

/* ==========================================================================
   media frame, corner brackets, like a tracking overlay
   ========================================================================== */

.frame { position: relative; background: var(--paper-2); border-radius: var(--radius); overflow: hidden; }
.frame > img, .frame > video { width: 100%; aspect-ratio: 16/9; object-fit: cover; }
.frame.tall > img, .frame.tall > video { aspect-ratio: auto; }
.frame::before, .frame::after {
  content: ""; position: absolute; width: 15px; height: 15px; pointer-events: none;
  border-color: var(--accent); opacity: .85; transition: opacity var(--t);
}
.frame::before { top: 7px; left: 7px;  border-top: 2px solid; border-left: 2px solid; }
.frame::after  { bottom: 7px; right: 7px; border-bottom: 2px solid; border-right: 2px solid; }

/* ==========================================================================
   featured project rows, GIF one side, text the other
   ========================================================================== */

.feature {
  display: grid; gap: clamp(1.25rem, 3.5vw, 2.75rem);
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
  padding-block: clamp(1.5rem, 3vw, 2.25rem);
}
.feature + .feature { border-top: 1px dashed var(--rule); }
@media (min-width: 860px) {
  .feature { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); }
  .feature.flip .feature-media { order: 2; }
}
.feature-media { position: relative; }
.feature-media a { display: block; border-radius: var(--radius); overflow: hidden; }
.feature-media .frame { border: 1px solid var(--rule); }
.feature-media img, .feature-media video { transition: transform 420ms cubic-bezier(.2,.7,.3,1); }
.feature-media a:hover img, .feature-media a:hover video { transform: scale(1.028); }

.feature h3 { font-size: clamp(1.35rem, 2.6vw, 1.75rem); margin-bottom: .3rem; letter-spacing: -.02em; }
.feature h3 a { color: var(--ink); }
.feature h3 a:hover { color: var(--accent-ink); text-decoration: none; }
.feature .sub { color: var(--slate); font-size: 1rem; margin-bottom: .7rem; font-weight: 500; }
.feature .meta { color: var(--ink-3); display: block; margin-bottom: .85rem; }
.feature p.desc { color: var(--ink-2); margin-bottom: 1rem; }
.feature .rank {
  position: absolute; top: -.6rem; left: -.6rem; z-index: 2;
  font-family: var(--mono); font-size: .7rem; font-weight: 700;
  background: var(--accent); color: #fff; padding: .18rem .5rem;
  border-radius: var(--radius); letter-spacing: .06em;
}

/* ==========================================================================
   tag chips
   ========================================================================== */

.chips { display: flex; flex-wrap: wrap; gap: .4rem; }
.chip {
  display: inline-block; border: 1px solid var(--rule-2); background: var(--card);
  color: var(--ink-2); padding: .3rem .72rem; border-radius: 100px;
  text-decoration: none; white-space: nowrap;
}
a.chip:hover { border-color: var(--accent); color: var(--accent-ink); text-decoration: none; }

.filterbar {
  /* Sticks directly under the header, which measures itself into --head-h (see
     site.js). The 1px back-off is deliberate: overlapping the header by a hair
     is invisible, since the .85rem padding below absorbs it and the header
     paints on top at a higher z-index, whereas falling a hair short leaves a
     slit that project cards visibly scroll through. Round toward overlap. */
  position: sticky; top: calc(var(--head-h) - 1px); z-index: 30;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--rule);
  padding-block: .85rem;
  margin-bottom: clamp(1.75rem, 4vw, 2.5rem);
}
.filterbar-row { display: flex; align-items: center; gap: .9rem; }
.filterbar .inner { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; flex: 1 1 auto; }
.filterbar button {
  font-family: var(--mono); font-size: .82rem; letter-spacing: .06em;
  text-transform: uppercase; cursor: pointer;
  border: 1px solid var(--rule-2); background: var(--card); color: var(--ink-2);
  padding: .46rem .95rem; border-radius: 100px;
  transition: all var(--t);
}
.filterbar button:hover { border-color: var(--accent); color: var(--accent-ink); }
.filterbar button[aria-pressed="true"] {
  background: var(--accent); border-color: var(--accent); color: #fff;
}
.filterbar .count { margin-left: auto; color: var(--ink-3); white-space: nowrap; }

/* The header is two rows tall on phones, so sticking the filter bar under it
   would hide the top row of cards. Let it scroll away instead. */
@media (max-width: 720px) {
  /* Nine wrapping chips at 44px each ate half the viewport before a single
     project was visible. One scrollable row instead, tap height preserved. */
  /* All chips visible, wrapped into a few compact rows. No horizontal scroll:
     a filter you have to swipe to find is a filter you do not use. */
  .filterbar { position: static; padding-block: .5rem; }
  .filterbar-row { display: block; }
  .filterbar .count { display: block; margin: 0 0 .4rem; font-size: .64rem; }
  .filterbar .inner { flex-wrap: wrap; gap: .3rem; }
  .filterbar button {
    flex: 0 0 auto;
    font-size: .52rem; line-height: 1.25; letter-spacing: .02em;
    padding: .14rem .48rem; border-radius: 100px;
  }
  .filterbar button .chip-n { margin-left: .35em; }

  /* tag chips on the project cards, same treatment */
  .chip { font-size: .52rem; padding: .12rem .45rem; letter-spacing: .02em; }
  .card .chips { gap: .28rem; }
}

/* ==========================================================================
   project card grid
   ========================================================================== */

.grid {
  display: grid; gap: clamp(1.1rem, 2.4vw, 1.8rem);
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.card {
  display: flex; flex-direction: column;
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--card); overflow: hidden;
  transition: border-color var(--t), transform var(--t), box-shadow var(--t);
}
.card:hover {
  border-color: var(--accent);
  transform: translateY(-3px);
  box-shadow: 0 10px 28px -18px rgba(20,22,26,.4);
}
.card .thumb { position: relative; display: block; background: var(--paper-2); }
.card .thumb img, .card .thumb video { width: 100%; aspect-ratio: 16/9; object-fit: cover; }
.card .badges { position: absolute; top: .5rem; left: .5rem; display: flex; gap: .3rem; }
.card .badge {
  font-family: var(--mono); font-size: .72rem; letter-spacing: .06em;
  text-transform: uppercase; padding: .22rem .5rem; border-radius: 2px;
  background: color-mix(in srgb, var(--ink) 82%, transparent); color: var(--paper);
  backdrop-filter: blur(4px);
}
.card .badge.star { background: var(--accent); color: #fff; }

.card .body { padding: 1.15rem 1.2rem 1.25rem; display: flex; flex-direction: column; flex: 1; }
.card .meta { color: var(--ink-3); margin-bottom: .35rem; }
.card h3 { font-size: 1.15rem; margin-bottom: .3rem; letter-spacing: -.014em; }
.card h3 a { color: var(--ink); }
.card h3 a:hover { color: var(--accent-ink); text-decoration: none; }
.card p { font-size: 1rem; color: var(--ink-2); margin-bottom: .85rem; line-height: 1.55; }
.card .chips { margin-top: auto; }

.card[hidden] { display: none; }

/* ==========================================================================
   project detail page
   ========================================================================== */

.backlink {
  font-family: var(--mono); font-size: .73rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3);
  display: inline-block; margin-bottom: 1.5rem;
}
.backlink:hover { color: var(--accent-ink); text-decoration: none; }

.proj-head { padding-block: clamp(2rem, 5vw, 3rem) clamp(1.25rem, 3vw, 2rem); }
.proj-head h1 { font-size: clamp(1.9rem, 4.4vw, 2.9rem); margin-bottom: .35rem; }
.proj-head .sub { font-size: clamp(1.05rem, 2.2vw, 1.28rem); color: var(--slate); font-weight: 500; margin-bottom: 1rem; }
.proj-head .meta { color: var(--ink-3); display: block; margin-bottom: .2rem; }
.proj-head .venue { color: var(--accent-ink); font-family: var(--mono); font-size: .755rem;
                    letter-spacing: .07em; text-transform: uppercase; }
.proj-head .chips { margin-top: 1rem; }

.proj-hero { margin-block: clamp(1.25rem, 3vw, 2rem); }
.proj-hero .frame { border: 1px solid var(--rule); }
.proj-hero { max-width: 900px; }
.proj-hero .frame > img, .proj-hero .frame > video { aspect-ratio: auto; max-height: 46vh; object-fit: contain; background: var(--paper-2); }

.prose { max-width: 68ch; }
.prose h2 {
  font-family: var(--mono); font-size: .92rem; letter-spacing: .11em;
  text-transform: uppercase; color: var(--accent-ink);
  margin: 2.4rem 0 .8rem; font-weight: 600;
}
.prose ul { margin: 0 0 1.1em; padding-left: 1.15em; }
.prose li { margin-bottom: .5em; color: var(--ink-2); }
.prose p { color: var(--ink-2); }

/* Pull quote, not a scoreboard. The figure already lives in the sentence. */
.result {
  margin: 1.9rem 0;
  padding: .1rem 0 .1rem 1.4rem;
  border-left: 3px solid var(--accent);
  font-size: 1.3rem; line-height: 1.5; letter-spacing: -.011em;
  color: var(--ink); font-weight: 450;
}

/* what worked / what didn't */
.prose ul.ticks, .prose ul.crosses { list-style: none; padding-left: 0; }
.prose ul.ticks li, .prose ul.crosses li {
  position: relative; padding-left: 1.7rem; margin-bottom: .6em;
}
.prose ul.ticks li::before, .prose ul.crosses li::before {
  position: absolute; left: 0; top: 0;
  font-family: var(--mono); font-size: .95em; font-weight: 700;
}
.prose ul.ticks li::before   { content: "+"; color: #2C8C4A; }
.prose ul.crosses li::before { content: "\2212"; color: #C0562B; }

/* provenance: where each figure on the page came from */
.sources { margin-top: 2.5rem; padding-top: 1.25rem; border-top: 1px dashed var(--rule); }
.sources h3 {
  font-family: var(--mono); font-size: .72rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3); font-weight: 600; margin-bottom: .6rem;
}
.sources ul { list-style: none; margin: 0; padding: 0; }
.sources li {
  font-family: var(--mono); font-size: .7rem; line-height: 1.75;
  color: var(--ink-3); letter-spacing: .01em;
}
.sources li b { color: var(--ink-2); font-weight: 600; }

/* diagrams and plots letterbox instead of being cropped to 16:9 */
.card .thumb img.fit-contain, .card .thumb video.fit-contain,
.robot img.fit-contain, .robot video.fit-contain {
  object-fit: contain; background: var(--paper-2);
}
.frame.fit-contain > img, .frame.fit-contain > video {
  object-fit: contain; background: var(--paper-2);
}

.note {
  font-size: .9rem; color: var(--ink-3); font-style: italic;
  border-left: 2px solid var(--rule-2); padding-left: .9rem; margin: 1.25rem 0;
}

/* ==========================================================================
   gallery
   Photographs run from a 3:1 group panorama to portrait phone shots. Rather
   than crop them all to one box, each figure carries its own aspect ratio as
   --ar and flexes in proportion to it, so a row justifies to a common height
   and nothing loses its edges.
   ========================================================================== */

.gal-head { padding-top: clamp(2rem, 5vw, 3.4rem); }
.gal-head h1 { margin-bottom: .5rem; }
.gal-group { margin-top: clamp(2.4rem, 5vw, 3.6rem); }
.gal-note { color: var(--ink-2); max-width: 68ch; margin: 0 0 1.5rem; }

.gal-grid { display: flex; flex-wrap: wrap; gap: 1.15rem; align-items: flex-start; }
.gal-grid figure {
  margin: 0;
  flex: var(--ar, 1) 1 calc(var(--ar, 1) * 265px);
  min-width: min(260px, 100%);
}
.gal-grid img {
  display: block; width: 100%; height: auto; aspect-ratio: var(--ar, 1);
  object-fit: cover; background: var(--paper-2);
  border: 1px solid var(--rule); border-radius: var(--radius);
}
.gal-grid figcaption {
  margin-top: .55rem; font-size: .86rem; line-height: 1.6; color: var(--ink-3);
  max-width: 48ch;
}
/* Soak up the slack on the final row, so a photo left on its own keeps its
   size instead of stretching to the full width of the page. */
.gal-grid::after { content: ""; flex-grow: 5; }
@media (max-width: 640px) {
  .gal-grid { gap: 1.4rem; }
  .gal-grid figure { flex-basis: 100%; min-width: 100%; }
  .gal-grid figcaption { font-size: .82rem; }
}

.figs { display: grid; gap: 1.5rem; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.fig .frame { border: 1px solid var(--rule); }
.fig .frame > img, .fig .frame > video { aspect-ratio: auto; background: var(--card); object-fit: contain; }
.fig figcaption {
  font-family: var(--mono); font-size: .71rem; line-height: 1.5;
  color: var(--ink-3); margin-top: .55rem; letter-spacing: .015em; text-transform: none;
}

.projnav {
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  border-top: 1px solid var(--rule); padding-top: 1.5rem; margin-top: 1rem;
}
.projnav a { font-family: var(--mono); font-size: .74rem; letter-spacing: .07em; text-transform: uppercase; }
.projnav .spacer { flex: 1; }

/* ==========================================================================
   experience / publications / talks
   ========================================================================== */

.timeline { display: grid; gap: 1.9rem; }
.entry { display: grid; grid-template-columns: 11rem minmax(0, 1fr); gap: 1.5rem; }
.entry .when { font-family: var(--mono); font-size: .82rem; letter-spacing: .05em;
               color: var(--ink-3); padding-top: .28em; }
.entry .when span { display: block; text-transform: none; letter-spacing: .02em; margin-top: .2em; }
.entry h3 { font-size: 1.18rem; margin-bottom: .1rem; }
.entry .role { color: var(--slate); font-weight: 500; margin-bottom: .5rem; font-size: .97rem; }
.entry ul { margin: 0; padding-left: 1.1em; }
.entry li { color: var(--ink-2); margin-bottom: .4em; font-size: 1.02rem; }
@media (max-width: 680px) {
  .entry { grid-template-columns: 1fr; gap: .35rem; }
  .entry .when span { display: inline; margin-left: .5em; }
}

.exp-media { margin: .9rem 0 0; max-width: 420px; }
.exp-media .frame { border: 1px solid var(--rule); }
.exp-media img { aspect-ratio: 16/9; object-fit: cover; }
.exp-media figcaption {
  font-family: var(--mono); font-size: .68rem; line-height: 1.5;
  color: var(--ink-3); margin-top: .45rem;
}

.pubs { display: grid; gap: 1.9rem; }
.pub { display: grid; grid-template-columns: 168px minmax(0, 1fr); gap: 1.4rem; align-items: start; }
.pub .thumb .frame { border: 1px solid var(--rule); }
.pub .thumb img { aspect-ratio: 16/10; object-fit: cover; }
.pub .thumb.empty {
  aspect-ratio: 16/10; border: 1px dashed var(--rule-2); border-radius: var(--radius);
  display: grid; place-items: center; color: var(--ink-3);
  font-family: var(--mono); font-size: .68rem; letter-spacing: .08em; background: var(--paper-2);
}
.pub h3 { font-size: 1.14rem; margin-bottom: .3rem; line-height: 1.35; }
.pub h3 a { color: var(--ink); }
.pub .authors { font-size: .92rem; color: var(--ink-2); margin-bottom: .25rem; }
.pub .venue { font-size: .92rem; color: var(--slate); margin-bottom: .55rem; }
.pub .venue .badge {
  font-family: var(--mono); font-size: .66rem; letter-spacing: .07em; text-transform: uppercase;
  background: var(--accent); color: #fff; padding: .1rem .4rem; border-radius: 2px; margin-left: .4rem;
}
@media (max-width: 620px) { .pub { grid-template-columns: 1fr; gap: .8rem; } .pub .thumb { max-width: 220px; } }

.talks { display: grid; gap: 1.6rem; }
.talk { display: grid; grid-template-columns: 7rem minmax(0, 1fr); gap: 1.4rem; }
.talk .when { font-family: var(--mono); font-size: .74rem; color: var(--accent-ink); padding-top: .3em; }
.talk h3 { font-size: 1.03rem; margin-bottom: .15rem; line-height: 1.4; }
.talk .where { font-size: .9rem; color: var(--slate); margin-bottom: .4rem; }
.talk p { font-size: .95rem; color: var(--ink-2); margin-bottom: .55rem; }
@media (max-width: 620px) { .talk { grid-template-columns: 1fr; gap: .25rem; } }

.awards { list-style: none; margin: 0; padding: 0; }
.awards li {
  display: grid; grid-template-columns: 6rem minmax(0, 1fr); gap: 1rem;
  padding: .45rem 0; border-bottom: 1px dashed var(--rule); color: var(--ink-2);
}
.awards li:last-child { border-bottom: 0; }
.awards .yr { font-family: var(--mono); font-size: .74rem; color: var(--ink-3); padding-top: .2em; }

.simple-list { list-style: none; margin: 0; padding: 0; }
.simple-list li { padding: .35rem 0; color: var(--ink-2); border-bottom: 1px dashed var(--rule); }
.simple-list li:last-child { border-bottom: 0; }

/* ==========================================================================
   footer
   ========================================================================== */

.site-foot {
  border-top: 1px solid var(--rule); background: var(--paper-2);
  padding-block: 2.5rem 3rem; margin-top: 0;
}
.site-foot .wrap { display: flex; gap: 1.5rem; flex-wrap: wrap; align-items: flex-start; }
.site-foot .note { font-family: var(--mono); font-size: .72rem; letter-spacing: .05em;
                   color: var(--ink-3); line-height: 1.8; text-transform: none; }
.site-foot .linkrow { margin-top: 0; margin-left: auto; }

/* ==========================================================================
   misc
   ========================================================================== */

.lede { font-size: 1.08rem; color: var(--ink-2); max-width: 62ch; }
.center { text-align: center; }
.stack > * + * { margin-top: 1.1rem; }


/* ==========================================================================
   phones, the desktop scale is deliberately large, which is too much at
   390px. Everything below is mobile-only; desktop is untouched.
   ========================================================================== */

@media (max-width: 720px) {
  body { font-size: 15px; line-height: 1.5; }

  h1 { font-size: clamp(1.85rem, 8.5vw, 2.5rem); }
  h2 { font-size: clamp(1.3rem, 5.5vw, 1.6rem); }
  h3 { font-size: 1.08rem; }

  .mono, .eyebrow, .chip, .meta, .datecol, .linkrow a, .count { font-size: .68rem; }

  /* header: one tight row for the brand, one for the links */
  /* brand on its own line, nav on the next, so nothing gets clipped */
  .site-head .wrap { min-height: 0; padding-block: .3rem; flex-wrap: wrap; row-gap: .1rem; }
  .brand { font-size: .76rem; }
  .site-nav { flex-wrap: nowrap; justify-content: space-between; gap: 0; }
  .site-nav a { font-size: .68rem; letter-spacing: .02em; padding-inline: .3rem; white-space: nowrap; }
  /* CV also sits in the hero link row, so drop it here to keep one clean line */
  .site-nav a[href$="resume.pdf"] { display: none; }

  /* hero */
  .hero { padding-block: 1.75rem 1.5rem; }
  .hero .status {
    font-size: .66rem; letter-spacing: .06em;
    padding: .3rem .7rem .3rem .55rem; margin-bottom: .9rem;
  }
  .hero .tagline { font-size: 1.08rem; margin-bottom: 1.1rem; }
  .hero .bio { font-size: .92rem; }
  .hero .bio p { margin-bottom: .8em; }
  .linkrow { gap: .45rem; margin-top: 1.1rem; }
  .linkrow a { padding: .42rem .6rem; font-size: .64rem; }
  .linkrow svg { width: 13px; height: 13px; }

  /* Portrait leads on a phone. Explicit box: `width:100%` inside a
     shrink-wrapped flex item collapses, so set both dimensions outright. */
  .hero-grid { display: flex; flex-direction: column-reverse; align-items: flex-start; gap: 1.1rem; }
  .portrait {
    width: 168px; max-width: 168px; height: 168px;
    aspect-ratio: auto; object-fit: cover; object-position: 50% 22%;
  }

  /* sections */
  section { padding-block: 2rem; }
  p { margin-bottom: .85em; }
  .sec-head { gap: .7rem; margin-bottom: 1.25rem; }
  .sec-head .num { font-size: .74rem; }
  .sec-head h2 { font-size: 1.3rem; }
  .sec-head .more { font-size: .7rem; }

  /* updates */
  .updates li { padding-block: .55rem; }
  .updates .txt { font-size: .9rem; }

  /* robot rail */
  .robot { width: 190px; }
  .robot .cap { font-size: .68rem; }
  .robot-strip .label { font-size: .72rem; }

  /* cards and features */
  .card .body { padding: .9rem 1rem 1rem; }
  .card h3 { font-size: 1.05rem; }
  .card p { font-size: .88rem; }
  .feature h3 { font-size: 1.3rem; }
  .feature .sub { font-size: .95rem; }
  .feature p.desc { font-size: .95rem; }

  /* project pages */
  .proj-head { padding-block: 1.5rem 1rem; }
  .proj-head h1 { font-size: clamp(1.7rem, 7.5vw, 2.2rem); }
  .proj-head .sub { font-size: 1.02rem; }
  .prose h2 { font-size: .82rem; margin-top: 1.9rem; }
  .prose p, .prose li { font-size: .91rem; }
  .result { font-size: 1.08rem; padding-left: 1rem; margin: 1.4rem 0; }
  .figs { gap: 1.1rem; grid-template-columns: 1fr; }
  .fig figcaption { font-size: .7rem; }

  /* lists */
  .lede { font-size: 1.02rem; }
  .entry li, .pub .authors, .pub .venue { font-size: .93rem; }
  .talk p { font-size: .93rem; }
  .sources li { font-size: .68rem; }
}

@media (max-width: 400px) {
  body { font-size: 14.5px; }
  .portrait { width: 148px; max-width: 148px; height: 148px; }
  .robot { width: 172px; }
  .site-nav a { font-size: .64rem; padding-inline: .22rem; }
}

/* ==========================================================================
   about page, a single readable column in the academic-site idiom
   ========================================================================== */

.about-head {
  display: flex; align-items: center; gap: 1.75rem; flex-wrap: wrap;
  padding-top: clamp(2.25rem, 5vw, 3.5rem);
  padding-bottom: clamp(1.25rem, 3vw, 2rem);
  max-width: 860px;
}
.about-portrait {
  width: 168px; height: 168px; flex: none;
  border-radius: 50%; object-fit: cover; object-position: 50% 22%;
  border: 1px solid var(--rule-2);
}
.about-head h1 { font-size: clamp(1.9rem, 4vw, 2.6rem); margin-bottom: .2rem; }
.about-role {
  font-family: var(--mono); font-size: .8rem; letter-spacing: .07em;
  text-transform: uppercase; color: var(--slate); margin-bottom: .35rem;
}
.about-head .linkrow { margin-top: .9rem; }

.about-body { max-width: 860px; padding-bottom: clamp(1rem, 3vw, 2rem); }
.about-block { padding-block: 0 clamp(1.5rem, 3vw, 2.1rem); border: 0; }
.about-block + .about-block { border-top: 1px solid var(--rule); padding-top: clamp(1.5rem, 3vw, 2.1rem); }
.about-block h2 {
  font-family: var(--mono); font-size: .85rem; letter-spacing: .11em;
  text-transform: uppercase; color: var(--accent-ink);
  font-weight: 600; margin-bottom: .7rem;
}
.about-block p {
  font-size: 1.12rem; line-height: 1.68; color: var(--ink-2); margin: 0;
}
.about-block strong { color: var(--ink); font-weight: 620; }

@media (max-width: 720px) {
  .about-head { gap: 1.1rem; padding-top: 1.75rem; }
  .about-portrait { width: 116px; height: 116px; }
  .about-block p { font-size: 1rem; line-height: 1.6; }
  .about-block h2 { font-size: .78rem; }
}

/* ==========================================================================
   blog-style project body: figures sit beside the text, alternating sides
   ========================================================================== */

.prose.blog { max-width: 900px; }
.prose.blog::after { content: ""; display: block; clear: both; }

.fig-side { margin: .2rem 0 1.1rem; }
.fig-side .frame { border: 1px solid var(--rule); }
.fig-side figcaption {
  font-family: var(--mono); font-size: .69rem; line-height: 1.55;
  color: var(--ink-3); margin-top: .45rem; text-transform: none; letter-spacing: .01em;
}

@media (min-width: 860px) {
  .fig-side { width: 44%; }
  .fig-side.right { float: right; margin-left: 2rem; }
  .fig-side.left  { float: left;  margin-right: 2rem; }
  /* a heading must not wrap around the image above it */
  .prose.blog h2 { clear: both; }
}

.figs-rest { margin-top: clamp(2rem, 4vw, 3rem); }

/* ==========================================================================
   video cards: a large clickable block per YouTube link
   ========================================================================== */

.videos-wrap { margin-top: clamp(2.25rem, 5vw, 3.25rem); }
.video-cards {
  display: grid; gap: clamp(1rem, 2.2vw, 1.5rem);
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.video-card {
  display: block; text-decoration: none; overflow: hidden;
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--card);
  transition: border-color var(--t), transform var(--t), box-shadow var(--t);
}
.video-card:hover {
  border-color: var(--accent); text-decoration: none;
  transform: translateY(-3px); box-shadow: 0 10px 28px -18px rgba(20,22,26,.4);
}
.video-card .vthumb { position: relative; display: block; background: #000; }
.video-card img { width: 100%; aspect-ratio: 16/9; object-fit: cover; display: block; }
.video-card .play {
  position: absolute; inset: 0; display: grid; place-items: center;
}
.video-card .play svg { width: 68px; height: 48px; filter: drop-shadow(0 2px 6px rgba(0,0,0,.4)); }
.video-card .play .bg    { fill: rgba(20,22,26,.72); transition: fill var(--t); }
.video-card .play .arrow { fill: #fff; }
.video-card:hover .play .bg { fill: var(--accent); }
.video-card .vlabel {
  display: block; padding: .8rem 1rem .9rem;
  font-family: var(--mono); font-size: .78rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-2);
}
.video-card:hover .vlabel { color: var(--accent-ink); }

.proj-foot { margin-top: clamp(2.25rem, 5vw, 3.25rem); padding-bottom: clamp(2.5rem, 6vw, 4rem); }

@media (max-width: 720px) {
  .proj-hero .frame > img, .proj-hero .frame > video { max-height: 40vh; }
  .fig-side figcaption { font-size: .66rem; }
  .video-card .play svg { width: 54px; height: 38px; }
  .video-card .vlabel { font-size: .7rem; padding: .65rem .8rem .75rem; }
}

/* Active filter chips are white-on-accent, which is fine on paper but only
   2.34:1 against the lighter dark-mode accent. Use dark text there instead. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .filterbar button[aria-pressed="true"] { color: #14161A; }
  :root:not([data-theme="light"]) .card .badge.star { color: #14161A; }
  :root:not([data-theme="light"]) .pub .venue .badge { color: #14161A; }
}
:root[data-theme="dark"] .filterbar button[aria-pressed="true"],
:root[data-theme="dark"] .card .badge.star,
:root[data-theme="dark"] .pub .venue .badge { color: #14161A; }

/* Figures from papers are drawn on white plates, which glare on a dark page.
   Knock them back slightly so they sit on the surface instead of floating. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .fig img, :root:not([data-theme="light"]) .fig-side img,
  :root:not([data-theme="light"]) .pub .thumb img { filter: brightness(.9) contrast(1.02); }
}
:root[data-theme="dark"] .fig img,
:root[data-theme="dark"] .fig-side img,
:root[data-theme="dark"] .pub .thumb img { filter: brightness(.9) contrast(1.02); }

.filterbar button .chip-n { opacity: .55; margin-left: .5em; font-variant-numeric: tabular-nums; }

/* Postscript under the intro: an aside, not a fourth paragraph. */
.bio-ps {
  margin: 1.1rem 0 0; max-width: 62ch;
  font-size: .93rem; line-height: 1.6; color: var(--ink-3);
  padding-left: .95rem; border-left: 2px solid var(--rule-2);
}
.bio-ps .ps-mark {
  font-family: var(--mono); font-size: .68rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent-ink);
  margin-right: .45em;
}
.bio-ps .ps-mark::after { content: ":"; }
.bio-ps strong { color: var(--ink-2); font-weight: 620; }
@media (max-width: 720px) {
  .bio-ps { font-size: .88rem; margin-top: .9rem; padding-left: .8rem; }
}

.rail-credit {
  margin: .9rem 0 0; font-family: var(--mono); font-size: .68rem; line-height: 1.6;
  color: var(--ink-3); letter-spacing: .01em; max-width: 78ch;
}
.rail-credit em { font-style: italic; }
@media (max-width: 720px) { .rail-credit { font-size: .62rem; } }
